Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ It demonstrates:
- one local skill (`/example-local`)
- one plugin-bundled skill (`/example-bundle-help`)
- one bundle-only plugin (`app/plugins/example-bundle/plugin.yaml`) with no credential broker config
- installed plugin packages (`@sentry/junior-agent-browser`, `@sentry/junior-github`, `@sentry/junior-hex`, `@sentry/junior-linear`, `@sentry/junior-notion`, `@sentry/junior-sentry`, `@sentry/junior-vercel`)
- installed plugin packages (`@sentry/junior-agent-browser`, `@sentry/junior-datadog`, `@sentry/junior-github`, `@sentry/junior-hex`, `@sentry/junior-linear`, `@sentry/junior-notion`, `@sentry/junior-sentry`, `@sentry/junior-vercel`)

## Run

Expand Down Expand Up @@ -38,7 +38,7 @@ Copy `.env.example` and set:

## Wiring

- `plugin-packages.ts` is the single source of truth for installed plugin packages in this app
- `nitro.config.ts` passes that list to `juniorNitro()` so plugin content is copied into the build output
- `server.ts` registers trusted runtime plugins, including the dashboard plugin, through `createApp({ plugins: [...] })`
- `plugins.ts` is the single source of truth for installed plugin registrations and trusted runtime plugins in this app
- `nitro.config.ts` points `juniorNitro()` at `./plugins` so plugin content is copied into the build output and exposed to runtime through the virtual config module
- `server.ts` calls `createApp()` without repeating the plugin list
- root `pnpm dev` starts a local heartbeat loop that calls `/api/internal/heartbeat` every minute, matching the production cron pulse used for trusted plugin heartbeats and stale dispatch recovery; it also defaults `JUNIOR_BASE_URL` to the local server when unset so signed internal callbacks can recover dispatched runs
5 changes: 1 addition & 4 deletions apps/example/nitro.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { defineConfig } from "nitro";
import { juniorNitro } from "@sentry/junior/nitro";
import { examplePluginPackages } from "./plugin-packages";

export default defineConfig({
preset: "vercel",
modules: [
juniorNitro({
plugins: {
packages: examplePluginPackages,
},
plugins: "./plugins",
}),
],
routes: {
Expand Down
10 changes: 0 additions & 10 deletions apps/example/plugin-packages.ts

This file was deleted.

22 changes: 22 additions & 0 deletions apps/example/plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineJuniorPlugins } from "@sentry/junior";
import { juniorDashboardPlugin } from "@sentry/junior-dashboard";
import { githubPlugin } from "@sentry/junior-github";
import { exampleDashboardAuthRequired } from "./dashboard.ts";

export const plugins = defineJuniorPlugins([
juniorDashboardPlugin({
authRequired: exampleDashboardAuthRequired(),
allowedGoogleDomains: ["sentry.io"],
}),
"@sentry/junior-agent-browser",
"@sentry/junior-datadog",
githubPlugin({
botNameEnv: "GITHUB_APP_BOT_NAME",
botEmailEnv: "GITHUB_APP_BOT_EMAIL",
}),
"@sentry/junior-hex",
"@sentry/junior-linear",
"@sentry/junior-notion",
"@sentry/junior-sentry",
"@sentry/junior-vercel",
]);
8 changes: 0 additions & 8 deletions apps/example/server.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { createApp } from "@sentry/junior";
import { juniorDashboardPlugin } from "@sentry/junior-dashboard";
import { initSentry } from "@sentry/junior/instrumentation";
import { exampleDashboardAuthRequired } from "./dashboard";

initSentry();

const app = await createApp({
plugins: [
juniorDashboardPlugin({
authRequired: exampleDashboardAuthRequired(),
allowedGoogleDomains: ["sentry.io"],
}),
],
configDefaults: {
"sentry.org": "sentry",
},
Expand Down
14 changes: 6 additions & 8 deletions packages/docs/src/content/docs/extend/_plugin-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ pnpm add @sentry/junior @sentry/junior-example

## Runtime setup

List the plugin in `juniorNitro({ plugins: { packages: [...] } })`:

```ts title="nitro.config.ts"
juniorNitro({
plugins: {
packages: ["@sentry/junior-example"],
},
});
Add the package name to the plugin set exported from `plugins.ts`:

```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";

export const plugins = defineJuniorPlugins(["@sentry/junior-example"]);
```

## Configure environment variables
Expand Down
14 changes: 6 additions & 8 deletions packages/docs/src/content/docs/extend/agent-browser-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ pnpm add @sentry/junior @sentry/junior-agent-browser

## Runtime setup

List the plugin in `juniorNitro({ plugins: { packages: [...] } })`:

```ts title="nitro.config.ts"
juniorNitro({
plugins: {
packages: ["@sentry/junior-agent-browser"],
},
});
Add the package name to the plugin set exported from `plugins.ts`:

```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";

export const plugins = defineJuniorPlugins(["@sentry/junior-agent-browser"]);
```

## Configure environment variables
Expand Down
95 changes: 38 additions & 57 deletions packages/docs/src/content/docs/extend/build-a-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Use local `app/plugins` while iterating in one app. Publish an npm package when

## Package layout

Use the same shape locally and in packages:
Manifest-only plugins use a data-only package:

```text title="Plugin package"
my-junior-plugin/
Expand All @@ -38,25 +38,8 @@ The package must include the manifest and skills in `package.json`:
}
```

If the package also exports trusted runtime hooks, include the entrypoint and
depend on `@sentry/junior-plugin-api`:

```json title="package.json"
{
"name": "@acme/junior-my-provider",
"type": "module",
"exports": {
".": {
"types": "./index.d.ts",
"default": "./index.js"
}
},
"files": ["index.d.ts", "index.js", "plugin.yaml", "skills"],
"dependencies": {
"@sentry/junior-plugin-api": "^0.53.0"
}
}
```
Use a JavaScript plugin factory instead of `plugin.yaml` when the package needs
trusted runtime hooks.

## Minimal manifest

Expand Down Expand Up @@ -117,32 +100,27 @@ Junior merges runtime dependency declarations from all loaded plugins and prepar

## Register the package

Install the plugin next to `@sentry/junior`, then list it in `juniorNitro`:
Install the plugin next to `@sentry/junior`, then add the package name to a
runtime-safe plugin set:

```ts title="nitro.config.ts"
import { defineConfig } from "nitro";
import { juniorNitro } from "@sentry/junior/nitro";
```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";

export default defineConfig({
modules: [
juniorNitro({
plugins: {
packages: ["@acme/junior-my-provider"],
},
}),
],
});
export const plugins = defineJuniorPlugins(["@acme/junior-my-provider"]);
```

Do not use the removed `pluginPackages` option. `junior check` rejects it.
Point `juniorNitro({ plugins: "./plugins" })` at that module and let
`createApp()` read the enabled set from Nitro's virtual module. Do not use the
removed `pluginPackages` or `plugins.packages` options; `junior check` rejects
both.

## Add trusted runtime hooks

Most plugins should stay manifest-only. Add trusted runtime hooks only when the
plugin must force deterministic behavior at a Junior-owned boundary, such as
installing sandbox helper files or mutating tool input/env before execution.
Trusted hooks are backend code and must be registered explicitly from app code;
Junior never loads them from `plugin.yaml`.
Most plugins should stay manifest-only. Use a JavaScript plugin definition only
when the plugin must force deterministic behavior at a Junior-owned boundary,
such as installing sandbox helper files or mutating tool input/env before
execution. Trusted hooks are backend code and must be registered explicitly from
app code; Junior never loads them from `plugin.yaml`.

Trusted hook contexts include `ctx.plugin` and `ctx.log`. Use `ctx.log` for
plugin-scoped structured logs instead of writing directly to stdout.
Expand All @@ -154,9 +132,10 @@ import { defineJuniorPlugin } from "@sentry/junior-plugin-api";

export function myProviderPlugin() {
return defineJuniorPlugin({
name: "my-provider",
pluginConfig: {
packages: ["@acme/junior-my-provider"],
manifest: {
name: "my-provider",
description: "My provider integration",
configKeys: ["org"],
},
hooks: {
async sandboxPrepare(ctx) {
Expand All @@ -176,24 +155,20 @@ export function myProviderPlugin() {
}
```

Register the trusted plugin from the app:
Do not ship `plugin.yaml` for the same plugin. The JavaScript definition owns
both the manifest surface and the trusted hooks. If the same package also ships
`skills/`, add `packageName: "@acme/junior-my-provider"` so Nitro copies those
skills into the deployment bundle.

```ts title="server.ts"
import { createApp } from "@sentry/junior";
import { myProviderPlugin } from "@acme/junior-my-provider";
Enable the trusted plugin from the app plugin module:

const app = await createApp({
plugins: [myProviderPlugin()],
});
```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";
import { myProviderPlugin } from "@acme/junior-my-provider";

export default app;
export const plugins = defineJuniorPlugins([myProviderPlugin()]);
```

`pluginConfig.packages` should include the package that contains `plugin.yaml`
so the trusted registration also loads the declarative provider metadata. Any
packages declared through `juniorNitro({ plugins })` continue to load; trusted
plugin package config is merged with the build-time plugin catalog.

Use `ctx.decision.replaceInput(...)` only with object-shaped tool input. Junior
rejects non-object replacements before the tool runs.

Expand All @@ -217,7 +192,10 @@ import { defineJuniorPlugin } from "@sentry/junior-plugin-api";

export function myProviderPlugin() {
return defineJuniorPlugin({
name: "my-provider",
manifest: {
name: "my-provider",
description: "My provider integration",
},
hooks: {
tools(ctx) {
return {
Expand Down Expand Up @@ -246,7 +224,10 @@ import { defineJuniorPlugin } from "@sentry/junior-plugin-api";

export function myProviderPlugin() {
return defineJuniorPlugin({
name: "my-provider",
manifest: {
name: "my-provider",
description: "My provider integration",
},
hooks: {
async heartbeat(ctx) {
const lastDispatch = await ctx.state.get<{ id: string }>(
Expand Down
14 changes: 6 additions & 8 deletions packages/docs/src/content/docs/extend/datadog-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@ pnpm add @sentry/junior @sentry/junior-datadog

## Runtime setup

List the plugin in `juniorNitro({ plugins: { packages: [...] } })`:

```ts title="nitro.config.ts"
juniorNitro({
plugins: {
packages: ["@sentry/junior-datadog"],
},
});
Add the package name to the plugin set exported from `plugins.ts`:

```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";

export const plugins = defineJuniorPlugins(["@sentry/junior-datadog"]);
```

Set Datadog credentials in your Junior deployment environment:
Expand Down
36 changes: 10 additions & 26 deletions packages/docs/src/content/docs/extend/github-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,19 @@ pnpm add @sentry/junior @sentry/junior-github

## Runtime setup

List the plugin in `juniorNitro({ plugins: { packages: [...] } })` so the
manifest, runtime dependencies, and bundled skills are copied into the deployed
function:

```ts title="nitro.config.ts"
juniorNitro({
plugins: {
packages: ["@sentry/junior-github"],
},
});
```

Register the trusted GitHub plugin in `createApp()` so Junior can enforce Git
commit attribution at runtime:
Add the trusted plugin factory to the plugin set exported from `plugins.ts`. The factory registers the GitHub manifest,
bundled skills, and Git commit attribution hooks together.

```ts title="server.ts"
import { createApp } from "@sentry/junior";
```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";
import { githubPlugin } from "@sentry/junior-github";

const app = await createApp({
plugins: [
githubPlugin({
botNameEnv: "GITHUB_APP_BOT_NAME",
botEmailEnv: "GITHUB_APP_BOT_EMAIL",
}),
],
});

export default app;
export const plugins = defineJuniorPlugins([
githubPlugin({
botNameEnv: "GITHUB_APP_BOT_NAME",
botEmailEnv: "GITHUB_APP_BOT_EMAIL",
}),
]);
```

## Configure environment variables
Expand Down
14 changes: 6 additions & 8 deletions packages/docs/src/content/docs/extend/hex-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@ pnpm add @sentry/junior @sentry/junior-hex

## Runtime setup

List the plugin in `juniorNitro({ plugins: { packages: [...] } })`:

```ts title="nitro.config.ts"
juniorNitro({
plugins: {
packages: ["@sentry/junior-hex"],
},
});
Add the package name to the plugin set exported from `plugins.ts`:

```ts title="plugins.ts"
import { defineJuniorPlugins } from "@sentry/junior";

export const plugins = defineJuniorPlugins(["@sentry/junior-hex"]);
```

## Auth model
Expand Down
Loading
Loading