@render-harness/cap-webhook-generic 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# `@render-harness/cap-webhook-generic`
|
|
2
|
+
|
|
3
|
+
Generic inbound webhook connector for agents in the Render harness.
|
|
4
|
+
|
|
5
|
+
Use this pack when an agent should receive webhook events from a service that does not have a dedicated capability pack yet.
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
Drop the pack into `render-harness.yaml`:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
capabilities:
|
|
13
|
+
- pack: "@render-harness/cap-webhook-generic"
|
|
14
|
+
config:
|
|
15
|
+
secretEnv: "WEBHOOK_SECRET"
|
|
16
|
+
signatureHeader: "X-Signature-256"
|
|
17
|
+
requireSignature: true
|
|
18
|
+
textPath: "message.text"
|
|
19
|
+
metadataPaths:
|
|
20
|
+
sourceId: "id"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Set `WEBHOOK_SECRET` on the entry that loads the agent when signature verification is required.
|
|
24
|
+
|
|
25
|
+
## Connector
|
|
26
|
+
|
|
27
|
+
The pack mounts the `webhook-generic` connector at `/connectors/webhook-generic`.
|
|
28
|
+
|
|
29
|
+
Each accepted webhook delivery enqueues one harness run. The run's initial text comes from `textHeader`, `textPath`, the parsed body, or the raw body, in that order.
|
|
30
|
+
|
|
31
|
+
## Signatures
|
|
32
|
+
|
|
33
|
+
By default, the connector requires an HMAC signature:
|
|
34
|
+
|
|
35
|
+
- Secret env var: `WEBHOOK_SECRET`
|
|
36
|
+
- Signature header: `X-Signature-256`
|
|
37
|
+
- Algorithm: `sha256`
|
|
38
|
+
|
|
39
|
+
Set `requireSignature: false` only for trusted internal sources or local development.
|
|
40
|
+
|
|
41
|
+
## Config Keys
|
|
42
|
+
|
|
43
|
+
| Key | Type | Default | Notes |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `agent` | string | default agent | Agent name to enqueue runs for. |
|
|
46
|
+
| `userId` | string | `cap-webhook-generic` | User ID stored on enqueued runs. |
|
|
47
|
+
| `secretEnv` | string | `WEBHOOK_SECRET` | Env var that contains the HMAC secret. |
|
|
48
|
+
| `signatureHeader` | string | `X-Signature-256` | Header that contains the request signature. |
|
|
49
|
+
| `signaturePrefix` | string | none | Optional prefix to strip or match, such as `sha256=`. |
|
|
50
|
+
| `algorithm` | string | `sha256` | HMAC algorithm used for signature verification. |
|
|
51
|
+
| `idHeader` | string | none | Header used as the provider delivery ID and run ID seed. |
|
|
52
|
+
| `requireSignature` | boolean | `true` | Verifies signatures before enqueueing runs. |
|
|
53
|
+
| `textPath` | string | none | Dot path in the JSON body to use as the run text. |
|
|
54
|
+
| `textHeader` | string | none | Header to use as the run text. |
|
|
55
|
+
| `metadataPaths` | object | none | Map of metadata keys to dot paths in the JSON body. |
|
|
56
|
+
|
|
57
|
+
## Tools
|
|
58
|
+
|
|
59
|
+
This pack contributes a connector only. It does not register local tools.
|
|
60
|
+
|
|
61
|
+
## Test Commands
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
pnpm --filter @render-harness/cap-webhook-generic build
|
|
65
|
+
pnpm --filter @render-harness/cap-webhook-generic test
|
|
66
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,10 @@ import { definePack } from '@render-harness/registry';
|
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
|
|
6
|
+
// package.json
|
|
7
|
+
var package_default = {
|
|
8
|
+
version: "0.2.3"};
|
|
9
|
+
|
|
6
10
|
// src/extract.ts
|
|
7
11
|
function extractWebhookPayload(args) {
|
|
8
12
|
const cfg = args.config ?? {};
|
|
@@ -52,7 +56,7 @@ var DEFAULT_SECRET_ENV = "WEBHOOK_SECRET";
|
|
|
52
56
|
var DEFAULT_SIGNATURE_HEADER = "X-Signature-256";
|
|
53
57
|
var pack = definePack({
|
|
54
58
|
name: "cap-webhook-generic",
|
|
55
|
-
version:
|
|
59
|
+
version: package_default.version,
|
|
56
60
|
envSchema: [
|
|
57
61
|
{
|
|
58
62
|
name: DEFAULT_SECRET_ENV,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/extract.ts","../src/verify.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface ExtractConfig {\n textPath?: string;\n textHeader?: string;\n metadataPaths?: Record<string, string>;\n}\n\nexport interface ExtractedWebhook {\n text: string;\n metadata: Record<string, unknown>;\n}\n\nexport function extractWebhookPayload(args: {\n headers: Headers;\n parsedBody: unknown;\n rawBody: string;\n config?: ExtractConfig;\n}): ExtractedWebhook {\n const cfg = args.config ?? {};\n const headerText = cfg.textHeader ? args.headers.get(cfg.textHeader) : null;\n const pathText = cfg.textPath ? readPath(args.parsedBody, cfg.textPath) : undefined;\n const text = stringifyText(headerText ?? pathText ?? args.parsedBody ?? args.rawBody);\n const metadata: Record<string, unknown> = {};\n for (const [key, path] of Object.entries(cfg.metadataPaths ?? {})) {\n const value = readPath(args.parsedBody, path);\n if (value !== undefined) metadata[key] = value;\n }\n return { text, metadata };\n}\n\nexport function readPath(value: unknown, path: string): unknown {\n if (!path) return undefined;\n let cursor = value;\n for (const part of path.split(\".\")) {\n if (!part) return undefined;\n if (!cursor || typeof cursor !== \"object\") return undefined;\n cursor = (cursor as Record<string, unknown>)[part];\n }\n return cursor;\n}\n\nfunction stringifyText(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value, null, 2);\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nexport interface VerifyWebhookOptions {\n rawBody: string;\n signature: string | null;\n secret: string;\n algorithm?: string;\n prefix?: string;\n}\n\nexport function verifyWebhookSignature(opts: VerifyWebhookOptions): boolean {\n if (!opts.signature || opts.secret.length === 0) return false;\n const algorithm = opts.algorithm ?? \"sha256\";\n const expected = createHmac(algorithm, opts.secret).update(opts.rawBody).digest(\"hex\");\n const actual = opts.prefix ? stripPrefix(opts.signature, opts.prefix) : opts.signature;\n if (!actual) return false;\n\n const expectedBuf = Buffer.from(expected, \"hex\");\n const actualBuf = Buffer.from(actual, \"hex\");\n if (expectedBuf.length !== actualBuf.length) return false;\n return timingSafeEqual(expectedBuf, actualBuf);\n}\n\nfunction stripPrefix(value: string, prefix: string): string | null {\n return value.startsWith(prefix) ? value.slice(prefix.length) : null;\n}\n","import { createHash } from \"node:crypto\";\nimport { type ConnectorContribution, definePack, type PackContext } from \"@render-harness/registry\";\nimport { type ExtractConfig, extractWebhookPayload } from \"./extract.js\";\nimport { verifyWebhookSignature } from \"./verify.js\";\n\ninterface WebhookGenericConfig extends ExtractConfig {\n agent?: string;\n userId?: string;\n secretEnv?: string;\n signatureHeader?: string;\n signaturePrefix?: string;\n algorithm?: string;\n idHeader?: string;\n requireSignature?: boolean;\n}\n\nconst DEFAULT_SECRET_ENV = \"WEBHOOK_SECRET\";\nconst DEFAULT_SIGNATURE_HEADER = \"X-Signature-256\";\n\nconst pack = definePack({\n name: \"cap-webhook-generic\",\n version: \"0.1.0\",\n envSchema: [\n {\n name: DEFAULT_SECRET_ENV,\n required: false,\n secret: true,\n description: \"Secret used to verify generic webhook HMAC signatures.\",\n },\n ],\n connectors(ctx: PackContext): ConnectorContribution[] {\n const cfg = readConfig(ctx.config);\n return [\n {\n key: \"webhook-generic\",\n webhook: async (req, webCtx) => {\n const rawBody = await req.text();\n if (cfg.requireSignature) {\n const secret = ctx.env(cfg.secretEnv);\n if (!secret) {\n return json({ error: \"missing_secret\", env: cfg.secretEnv }, 500);\n }\n const verifyArgs = {\n rawBody,\n signature: req.headers.get(cfg.signatureHeader),\n secret,\n algorithm: cfg.algorithm,\n };\n const ok = verifyWebhookSignature(\n cfg.signaturePrefix ? { ...verifyArgs, prefix: cfg.signaturePrefix } : verifyArgs,\n );\n if (!ok) return json({ error: \"invalid_signature\" }, 401);\n }\n\n const parsedBody = parseBody(rawBody);\n const extracted = extractWebhookPayload({\n headers: req.headers,\n parsedBody,\n rawBody,\n config: cfg,\n });\n const agent = webCtx.resolveAgent(cfg.agent);\n const providerDeliveryId = cfg.idHeader ? req.headers.get(cfg.idHeader) : null;\n const runId = `webhook-${hash(providerDeliveryId ?? rawBody)}`;\n const result = await webCtx.enqueueRun({\n agentName: agent.name,\n agentVersion: agent.version,\n userId: cfg.userId ?? \"cap-webhook-generic\",\n runId,\n initialContent: [{ type: \"text\", text: extracted.text }],\n metadata: {\n connector: \"cap-webhook-generic\",\n deliveryId: providerDeliveryId,\n ...extracted.metadata,\n },\n });\n return json(result, result.status === \"enqueued\" ? 202 : 200);\n },\n },\n ];\n },\n});\n\nexport default pack;\n\ntype ResolvedWebhookGenericConfig = Required<\n Pick<WebhookGenericConfig, \"secretEnv\" | \"signatureHeader\" | \"algorithm\" | \"requireSignature\">\n> &\n Omit<WebhookGenericConfig, \"secretEnv\" | \"signatureHeader\" | \"algorithm\" | \"requireSignature\">;\n\nfunction readConfig(raw: Record<string, unknown>): ResolvedWebhookGenericConfig {\n const cfg: ResolvedWebhookGenericConfig = {\n secretEnv: stringValue(raw.secretEnv) ?? DEFAULT_SECRET_ENV,\n signatureHeader: stringValue(raw.signatureHeader) ?? DEFAULT_SIGNATURE_HEADER,\n algorithm: stringValue(raw.algorithm) ?? \"sha256\",\n requireSignature: raw.requireSignature !== false,\n };\n const agent = stringValue(raw.agent);\n if (agent) cfg.agent = agent;\n const userId = stringValue(raw.userId);\n if (userId) cfg.userId = userId;\n const signaturePrefix = stringValue(raw.signaturePrefix);\n if (signaturePrefix) cfg.signaturePrefix = signaturePrefix;\n const idHeader = stringValue(raw.idHeader);\n if (idHeader) cfg.idHeader = idHeader;\n const textPath = stringValue(raw.textPath);\n if (textPath) cfg.textPath = textPath;\n const textHeader = stringValue(raw.textHeader);\n if (textHeader) cfg.textHeader = textHeader;\n const metadataPaths = recordOfStrings(raw.metadataPaths);\n if (metadataPaths) cfg.metadataPaths = metadataPaths;\n return cfg;\n}\n\nfunction parseBody(rawBody: string): unknown {\n try {\n return JSON.parse(rawBody);\n } catch {\n return rawBody;\n }\n}\n\nfunction hash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 32);\n}\n\nfunction json(body: unknown, status = 200): Response {\n return Response.json(body, { status });\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction recordOfStrings(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const out: Record<string, string> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (typeof entry === \"string\") out[key] = entry;\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/extract.ts","../src/verify.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["{\n \"name\": \"@render-harness/cap-webhook-generic\",\n \"version\": \"0.2.3\",\n \"description\": \"Generic inbound webhook capability pack for the Render agent harness.\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\"\n ],\n \"keywords\": [\n \"render-harness-cap\",\n \"render-harness\",\n \"webhook\"\n ],\n \"renderHarness\": {\n \"gallery\": {\n \"label\": \"Generic webhook\",\n \"envHint\": \"WEBHOOK_SECRET\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run --passWithNoTests\"\n },\n \"dependencies\": {\n \"@render-harness/registry\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@render-harness/core\": \"workspace:*\",\n \"@types/node\": \"^25.6.2\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.5\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/render-lab/render-agent-harness.git\",\n \"directory\": \"packages/capabilities/cap-webhook-generic\"\n }\n}\n","export interface ExtractConfig {\n textPath?: string;\n textHeader?: string;\n metadataPaths?: Record<string, string>;\n}\n\nexport interface ExtractedWebhook {\n text: string;\n metadata: Record<string, unknown>;\n}\n\nexport function extractWebhookPayload(args: {\n headers: Headers;\n parsedBody: unknown;\n rawBody: string;\n config?: ExtractConfig;\n}): ExtractedWebhook {\n const cfg = args.config ?? {};\n const headerText = cfg.textHeader ? args.headers.get(cfg.textHeader) : null;\n const pathText = cfg.textPath ? readPath(args.parsedBody, cfg.textPath) : undefined;\n const text = stringifyText(headerText ?? pathText ?? args.parsedBody ?? args.rawBody);\n const metadata: Record<string, unknown> = {};\n for (const [key, path] of Object.entries(cfg.metadataPaths ?? {})) {\n const value = readPath(args.parsedBody, path);\n if (value !== undefined) metadata[key] = value;\n }\n return { text, metadata };\n}\n\nexport function readPath(value: unknown, path: string): unknown {\n if (!path) return undefined;\n let cursor = value;\n for (const part of path.split(\".\")) {\n if (!part) return undefined;\n if (!cursor || typeof cursor !== \"object\") return undefined;\n cursor = (cursor as Record<string, unknown>)[part];\n }\n return cursor;\n}\n\nfunction stringifyText(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value, null, 2);\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nexport interface VerifyWebhookOptions {\n rawBody: string;\n signature: string | null;\n secret: string;\n algorithm?: string;\n prefix?: string;\n}\n\nexport function verifyWebhookSignature(opts: VerifyWebhookOptions): boolean {\n if (!opts.signature || opts.secret.length === 0) return false;\n const algorithm = opts.algorithm ?? \"sha256\";\n const expected = createHmac(algorithm, opts.secret).update(opts.rawBody).digest(\"hex\");\n const actual = opts.prefix ? stripPrefix(opts.signature, opts.prefix) : opts.signature;\n if (!actual) return false;\n\n const expectedBuf = Buffer.from(expected, \"hex\");\n const actualBuf = Buffer.from(actual, \"hex\");\n if (expectedBuf.length !== actualBuf.length) return false;\n return timingSafeEqual(expectedBuf, actualBuf);\n}\n\nfunction stripPrefix(value: string, prefix: string): string | null {\n return value.startsWith(prefix) ? value.slice(prefix.length) : null;\n}\n","import { createHash } from \"node:crypto\";\nimport { type ConnectorContribution, definePack, type PackContext } from \"@render-harness/registry\";\nimport pkg from \"../package.json\" with { type: \"json\" };\nimport { type ExtractConfig, extractWebhookPayload } from \"./extract.js\";\nimport { verifyWebhookSignature } from \"./verify.js\";\n\ninterface WebhookGenericConfig extends ExtractConfig {\n agent?: string;\n userId?: string;\n secretEnv?: string;\n signatureHeader?: string;\n signaturePrefix?: string;\n algorithm?: string;\n idHeader?: string;\n requireSignature?: boolean;\n}\n\nconst DEFAULT_SECRET_ENV = \"WEBHOOK_SECRET\";\nconst DEFAULT_SIGNATURE_HEADER = \"X-Signature-256\";\n\nconst pack = definePack({\n name: \"cap-webhook-generic\",\n version: pkg.version,\n envSchema: [\n {\n name: DEFAULT_SECRET_ENV,\n required: false,\n secret: true,\n description: \"Secret used to verify generic webhook HMAC signatures.\",\n },\n ],\n connectors(ctx: PackContext): ConnectorContribution[] {\n const cfg = readConfig(ctx.config);\n return [\n {\n key: \"webhook-generic\",\n webhook: async (req, webCtx) => {\n const rawBody = await req.text();\n if (cfg.requireSignature) {\n const secret = ctx.env(cfg.secretEnv);\n if (!secret) {\n return json({ error: \"missing_secret\", env: cfg.secretEnv }, 500);\n }\n const verifyArgs = {\n rawBody,\n signature: req.headers.get(cfg.signatureHeader),\n secret,\n algorithm: cfg.algorithm,\n };\n const ok = verifyWebhookSignature(\n cfg.signaturePrefix ? { ...verifyArgs, prefix: cfg.signaturePrefix } : verifyArgs,\n );\n if (!ok) return json({ error: \"invalid_signature\" }, 401);\n }\n\n const parsedBody = parseBody(rawBody);\n const extracted = extractWebhookPayload({\n headers: req.headers,\n parsedBody,\n rawBody,\n config: cfg,\n });\n const agent = webCtx.resolveAgent(cfg.agent);\n const providerDeliveryId = cfg.idHeader ? req.headers.get(cfg.idHeader) : null;\n const runId = `webhook-${hash(providerDeliveryId ?? rawBody)}`;\n const result = await webCtx.enqueueRun({\n agentName: agent.name,\n agentVersion: agent.version,\n userId: cfg.userId ?? \"cap-webhook-generic\",\n runId,\n initialContent: [{ type: \"text\", text: extracted.text }],\n metadata: {\n connector: \"cap-webhook-generic\",\n deliveryId: providerDeliveryId,\n ...extracted.metadata,\n },\n });\n return json(result, result.status === \"enqueued\" ? 202 : 200);\n },\n },\n ];\n },\n});\n\nexport default pack;\n\ntype ResolvedWebhookGenericConfig = Required<\n Pick<WebhookGenericConfig, \"secretEnv\" | \"signatureHeader\" | \"algorithm\" | \"requireSignature\">\n> &\n Omit<WebhookGenericConfig, \"secretEnv\" | \"signatureHeader\" | \"algorithm\" | \"requireSignature\">;\n\nfunction readConfig(raw: Record<string, unknown>): ResolvedWebhookGenericConfig {\n const cfg: ResolvedWebhookGenericConfig = {\n secretEnv: stringValue(raw.secretEnv) ?? DEFAULT_SECRET_ENV,\n signatureHeader: stringValue(raw.signatureHeader) ?? DEFAULT_SIGNATURE_HEADER,\n algorithm: stringValue(raw.algorithm) ?? \"sha256\",\n requireSignature: raw.requireSignature !== false,\n };\n const agent = stringValue(raw.agent);\n if (agent) cfg.agent = agent;\n const userId = stringValue(raw.userId);\n if (userId) cfg.userId = userId;\n const signaturePrefix = stringValue(raw.signaturePrefix);\n if (signaturePrefix) cfg.signaturePrefix = signaturePrefix;\n const idHeader = stringValue(raw.idHeader);\n if (idHeader) cfg.idHeader = idHeader;\n const textPath = stringValue(raw.textPath);\n if (textPath) cfg.textPath = textPath;\n const textHeader = stringValue(raw.textHeader);\n if (textHeader) cfg.textHeader = textHeader;\n const metadataPaths = recordOfStrings(raw.metadataPaths);\n if (metadataPaths) cfg.metadataPaths = metadataPaths;\n return cfg;\n}\n\nfunction parseBody(rawBody: string): unknown {\n try {\n return JSON.parse(rawBody);\n } catch {\n return rawBody;\n }\n}\n\nfunction hash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 32);\n}\n\nfunction json(body: unknown, status = 200): Response {\n return Response.json(body, { status });\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction recordOfStrings(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const out: Record<string, string> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (typeof entry === \"string\") out[key] = entry;\n }\n return out;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@render-harness/cap-webhook-generic",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Generic inbound webhook capability pack for the Render agent harness.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
|
-
}
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
17
|
"dist"
|
|
@@ -27,18 +28,23 @@
|
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
|
-
"@render-harness/registry": "0.2.
|
|
31
|
+
"@render-harness/registry": "0.2.2"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@types/node": "^25.6.2",
|
|
34
35
|
"tsup": "^8.5.1",
|
|
35
36
|
"typescript": "^6.0.3",
|
|
36
37
|
"vitest": "^4.1.5",
|
|
37
|
-
"@render-harness/core": "0.2.
|
|
38
|
+
"@render-harness/core": "0.2.1"
|
|
38
39
|
},
|
|
39
40
|
"publishConfig": {
|
|
40
41
|
"access": "public"
|
|
41
42
|
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/render-lab/render-agent-harness.git",
|
|
46
|
+
"directory": "packages/capabilities/cap-webhook-generic"
|
|
47
|
+
},
|
|
42
48
|
"scripts": {
|
|
43
49
|
"build": "tsup",
|
|
44
50
|
"typecheck": "tsc --noEmit",
|