@secondlayer/cli 19.4.3 → 20.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/cli",
3
- "version": "19.4.3",
3
+ "version": "20.0.1",
4
4
  "description": "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,7 @@
21
21
  "import": "./dist/index.js"
22
22
  }
23
23
  },
24
- "files": ["dist", "templates", "README.md"],
24
+ "files": ["dist", "README.md"],
25
25
  "scripts": {
26
26
  "build": "bunup",
27
27
  "dev": "bunup --watch",
@@ -37,15 +37,15 @@
37
37
  "@biomejs/wasm-nodejs": "^1.9.0",
38
38
  "@dsnp/parquetjs": "~1.8.8",
39
39
  "@inquirer/prompts": "^8.2.0",
40
- "@secondlayer/bundler": "^0.7.0",
41
- "@secondlayer/scaffold": "^1.6.1",
42
- "@secondlayer/sdk": "^14.5.1",
43
- "@secondlayer/shared": "^11.24.1",
40
+ "@secondlayer/bundler": "^0.7.1",
41
+ "@secondlayer/scaffold": "^1.6.2",
42
+ "@secondlayer/sdk": "^15.0.0",
43
+ "@secondlayer/shared": "^12.0.0",
44
44
  "@secondlayer/stacks": "^6.2.0",
45
- "@secondlayer/subgraphs": "^6.6.2",
46
- "@secondlayer/verify": "^0.4.0",
45
+ "@secondlayer/subgraphs": "^7.0.1",
46
+ "@secondlayer/verify": "^0.5.0",
47
47
  "esbuild": "^0.28.2",
48
- "smol-toml": "^1.8.0",
48
+ "smol-toml": "^1.9.1",
49
49
  "zod": "^4.3.6"
50
50
  },
51
51
  "peerDependencies": {
@@ -1 +0,0 @@
1
- SIGNING_SECRET=
@@ -1,44 +0,0 @@
1
- # {{NAME}} — Cloudflare subscription receiver
2
-
3
- A [Cloudflare Workflows](https://developers.cloudflare.com/workflows/)
4
- instance triggered by a Secondlayer subscription via Cloudflare's
5
- `workflows/instances` REST API. "Workflows" here refers to Cloudflare's
6
- durable-execution product; it's separate from anything Secondlayer runs.
7
-
8
- ## Run
9
-
10
- ```bash
11
- bun install
12
- bunx wrangler login
13
- bunx wrangler dev
14
- ```
15
-
16
- `wrangler dev` spins up a local runtime. Your subscription URL should
17
- point at Cloudflare's API:
18
-
19
- ```
20
- https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/workflows/{{NAME}}/instances
21
- ```
22
-
23
- Provision the subscription with bearer auth:
24
-
25
- ```bash
26
- secondlayer webhooks create {{NAME}} --runtime cloudflare --auth-token <CF_API_TOKEN>
27
- ```
28
-
29
- You can also patch an existing subscription with
30
- `secondlayer webhooks update {{NAME}} --auth-token <CF_API_TOKEN>`.
31
-
32
- The token must have `Workflows: Edit` scope.
33
-
34
- ## Signature verification
35
-
36
- Cloudflare authenticates the API call with the bearer token. Inside the
37
- Workflows entrypoint, `event.payload.params._outboxId` is a stable dedup
38
- key if you want idempotent replay handling.
39
-
40
- ## Deploy
41
-
42
- ```bash
43
- bunx wrangler deploy
44
- ```
@@ -1,15 +0,0 @@
1
- {
2
- "name": "{{NAME}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "scripts": {
6
- "dev": "wrangler dev",
7
- "deploy": "wrangler deploy",
8
- "types": "wrangler types"
9
- },
10
- "devDependencies": {
11
- "@cloudflare/workers-types": "^4.20250101.0",
12
- "typescript": "^5",
13
- "wrangler": "^4.0.0"
14
- }
15
- }
@@ -1,34 +0,0 @@
1
- import {
2
- WorkflowEntrypoint,
3
- type WorkflowEvent,
4
- type WorkflowStep,
5
- } from "cloudflare:workers";
6
-
7
- interface Params {
8
- _type: string;
9
- _outboxId: string;
10
- [k: string]: unknown;
11
- }
12
-
13
- export class OnSubgraphEvent extends WorkflowEntrypoint<Env, Params> {
14
- async run(event: WorkflowEvent<Params>, step: WorkflowStep): Promise<void> {
15
- const params = event.payload;
16
- await step.do("handle", async () => {
17
- console.log("[subgraph event]", params._type, params);
18
- // TODO: plug in your business logic.
19
- return { ok: true };
20
- });
21
- }
22
- }
23
-
24
- interface Env {
25
- MY_WORKFLOW: Workflow<Params>;
26
- }
27
-
28
- export default {
29
- async fetch(_req: Request): Promise<Response> {
30
- return new Response(
31
- "Cloudflare Workflows receiver — trigger via the `workflows/instances` API.",
32
- );
33
- },
34
- };
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "skipLibCheck": true,
8
- "types": ["@cloudflare/workers-types"]
9
- }
10
- }
@@ -1,8 +0,0 @@
1
- name = "{{NAME}}"
2
- main = "src/index.ts"
3
- compatibility_date = "2025-01-01"
4
-
5
- [[workflows]]
6
- name = "{{NAME}}"
7
- binding = "MY_WORKFLOW"
8
- class_name = "OnSubgraphEvent"
@@ -1,2 +0,0 @@
1
- SIGNING_SECRET=
2
- PORT=3000
@@ -1,29 +0,0 @@
1
- # {{NAME}} — Inngest subscription receiver
2
-
3
- Inngest Dev Server with a function wired to `{{EVENT_NAME}}`. Events come
4
- from your Secondlayer subscription — Inngest handles retries, concurrency,
5
- and step-level state.
6
-
7
- ## Run
8
-
9
- ```bash
10
- bun install
11
- bun run dev
12
- ```
13
-
14
- This starts the Inngest dev UI at `http://localhost:8288`. Point your
15
- subscription URL at the Inngest event endpoint shown in the dev UI
16
- (typically `http://localhost:8288/e/{eventKey}` for local, or the hosted
17
- `https://inn.gs/e/{eventKey}` endpoint for cloud).
18
-
19
- ## Signature verification
20
-
21
- Inngest uses its own event key auth — there's no HMAC to verify. The event
22
- key in the URL IS the auth token. For self-hosted Inngest add an ingress
23
- allowlist so only the Secondlayer emitter can post.
24
-
25
- ## Deploy
26
-
27
- - **Inngest Cloud**: create an app at https://inngest.com, copy the event
28
- key, and set it in the subscription URL: `https://inn.gs/e/{EVENT_KEY}`.
29
- - **Self-host**: see https://www.inngest.com/docs/self-hosting
@@ -1,18 +0,0 @@
1
- {
2
- "name": "{{NAME}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "bunx inngest-cli@latest dev",
8
- "start": "bun --hot src/server.ts"
9
- },
10
- "dependencies": {
11
- "hono": "^4.6.0",
12
- "inngest": "^3.27.0"
13
- },
14
- "devDependencies": {
15
- "@types/bun": "latest",
16
- "typescript": "^5"
17
- }
18
- }
@@ -1,19 +0,0 @@
1
- import { Inngest } from "inngest";
2
-
3
- export const inngest = new Inngest({
4
- id: "{{NAME}}",
5
- });
6
-
7
- export const onSubgraphEvent = inngest.createFunction(
8
- { id: "on-subgraph-event", name: "On Subgraph Event" },
9
- { event: "{{EVENT_NAME}}" },
10
- async ({ event, step }) => {
11
- // `event.data` is the row payload delivered by Secondlayer.
12
- const row = event.data as Record<string, unknown>;
13
- await step.run("handle", async () => {
14
- console.log("[subgraph event]", event.name, row);
15
- // TODO: plug in your business logic — AI SDK, HTTP, DB writes, etc.
16
- return { ok: true };
17
- });
18
- },
19
- );
@@ -1,14 +0,0 @@
1
- import { Hono } from "hono";
2
- import { serve } from "inngest/hono";
3
- import { inngest, onSubgraphEvent } from "./inngest.ts";
4
-
5
- const app = new Hono();
6
- app.on(
7
- ["GET", "POST", "PUT"],
8
- "/api/inngest",
9
- serve({ client: inngest, functions: [onSubgraphEvent] }),
10
- );
11
-
12
- const PORT = Number.parseInt(process.env.PORT ?? "3000", 10);
13
- Bun.serve({ port: PORT, fetch: app.fetch });
14
- console.log(`{{NAME}} (Inngest host) listening on :${PORT}`);
@@ -1,11 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "esModuleInterop": true,
8
- "skipLibCheck": true,
9
- "types": ["bun-types"]
10
- }
11
- }
@@ -1,2 +0,0 @@
1
- SIGNING_SECRET=
2
- PORT=3000
@@ -1,36 +0,0 @@
1
- # {{NAME}} — Node.js subscription receiver
2
-
3
- Hono HTTP server that verifies Standard Webhooks signatures and routes events
4
- to your business logic. No framework lock-in.
5
-
6
- ## Run
7
-
8
- `.env` is written for you at `secondlayer webhooks create` time with the signing
9
- secret already populated. Lost it: `secondlayer webhooks rotate-secret {{NAME}}`.
10
-
11
- ```bash
12
- bun install
13
- bun run dev
14
- ```
15
-
16
- The server listens on `:3000`. Your subscription's URL should point at
17
- `http://<host>:3000/webhook`.
18
-
19
- ## Signature verification
20
-
21
- Every request is verified before your handler runs. Forged requests return
22
- `401`. The logic lives in `src/index.ts`; swap `@secondlayer/shared` for the
23
- [Svix verify library](https://docs.standardwebhooks.com/libraries) if you
24
- want to decouple from `@secondlayer/shared`:
25
-
26
- ```ts
27
- import { Webhook } from "standardwebhooks";
28
- const wh = new Webhook(process.env.SIGNING_SECRET!);
29
- const event = wh.verify(body, headers);
30
- ```
31
-
32
- ## Deploy
33
-
34
- Fly.io, Render, Railway, your own VM — anywhere that can run `bun` works.
35
- Expose port 3000, set `SIGNING_SECRET`, point the subscription URL at the
36
- public hostname.
@@ -1,18 +0,0 @@
1
- {
2
- "name": "{{NAME}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "bun --hot src/index.ts",
8
- "start": "bun src/index.ts"
9
- },
10
- "dependencies": {
11
- "@secondlayer/shared": "^4.2.0",
12
- "hono": "^4.6.0"
13
- },
14
- "devDependencies": {
15
- "@types/bun": "latest",
16
- "typescript": "^5"
17
- }
18
- }
@@ -1,53 +0,0 @@
1
- import { verify } from "@secondlayer/shared/crypto/standard-webhooks";
2
- import { Hono } from "hono";
3
-
4
- /**
5
- * Minimal Standard Webhooks receiver.
6
- *
7
- * The signing secret was shown ONCE when you ran `secondlayer webhooks create`.
8
- * If you lost it: secondlayer webhooks rotate-secret {{NAME}}
9
- */
10
-
11
- const SIGNING_SECRET = process.env.SIGNING_SECRET;
12
- if (!SIGNING_SECRET) {
13
- console.error(
14
- "SIGNING_SECRET not set. Copy .env.example → .env and fill it in.",
15
- );
16
- process.exit(1);
17
- }
18
-
19
- const app = new Hono();
20
-
21
- interface SubgraphEvent {
22
- type: string;
23
- timestamp: string;
24
- data: Record<string, unknown>;
25
- }
26
-
27
- app.post("/webhook", async (c) => {
28
- const body = await c.req.text();
29
- const headers: Record<string, string> = {};
30
- c.req.raw.headers.forEach((v, k) => {
31
- headers[k.toLowerCase()] = v;
32
- });
33
-
34
- if (!verify(body, headers, SIGNING_SECRET)) {
35
- console.warn("signature verification failed");
36
- return c.text("unauthorized", 401);
37
- }
38
-
39
- const event = JSON.parse(body) as SubgraphEvent;
40
- await onEvent(event);
41
- return c.text("ok", 200);
42
- });
43
-
44
- async function onEvent(event: SubgraphEvent): Promise<void> {
45
- // TODO: plug in your business logic. `event.type` is
46
- // `<subgraph>.<table>.<created|updated|deleted>` (the verb reflects the row
47
- // op); `event.data` is the row payload.
48
- console.log("[event]", event.type, event.data);
49
- }
50
-
51
- const PORT = Number.parseInt(process.env.PORT ?? "3000", 10);
52
- Bun.serve({ port: PORT, fetch: app.fetch });
53
- console.log(`{{NAME}} listening on :${PORT}`);
@@ -1,11 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "esModuleInterop": true,
8
- "skipLibCheck": true,
9
- "types": ["bun-types"]
10
- }
11
- }
@@ -1,2 +0,0 @@
1
- SIGNING_SECRET=
2
- TRIGGER_SECRET_KEY=
@@ -1,38 +0,0 @@
1
- # {{NAME}} — Trigger.dev subscription receiver
2
-
3
- A Trigger.dev v3 task that receives subgraph events via the
4
- `{task}/trigger` HTTP API.
5
-
6
- ## Run
7
-
8
- ```bash
9
- bun install
10
- bunx trigger.dev@latest init # follow prompts
11
- bun run dev
12
- ```
13
-
14
- The Trigger CLI provisions a project and shows the task endpoint URL. Your
15
- Secondlayer subscription URL should point at:
16
-
17
- ```
18
- https://api.trigger.dev/api/v1/tasks/{{TASK_ID}}/trigger
19
- ```
20
-
21
- Provision the subscription with bearer auth:
22
-
23
- ```bash
24
- secondlayer webhooks create {{NAME}} --runtime trigger --auth-token tr_secret_abc...
25
- ```
26
-
27
- You can also patch an existing subscription with
28
- `secondlayer webhooks update {{NAME}} --auth-token tr_secret_abc...`.
29
-
30
- ## Signature verification
31
-
32
- Trigger authenticates requests with the bearer token — there's no separate
33
- HMAC. Your secret IS the auth. Rotate via the Trigger dashboard when
34
- needed.
35
-
36
- ## Deploy
37
-
38
- Run `bunx trigger.dev@latest deploy` to push to Trigger Cloud.
@@ -1,17 +0,0 @@
1
- {
2
- "name": "{{NAME}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "npx trigger.dev@latest dev",
8
- "deploy": "npx trigger.dev@latest deploy"
9
- },
10
- "dependencies": {
11
- "@trigger.dev/sdk": "^3.3.0"
12
- },
13
- "devDependencies": {
14
- "@types/bun": "latest",
15
- "typescript": "^5"
16
- }
17
- }
@@ -1,15 +0,0 @@
1
- import { task } from "@trigger.dev/sdk/v3";
2
-
3
- /**
4
- * Task triggered by a Secondlayer subscription. The Secondlayer emitter
5
- * POSTs to this task's HTTP endpoint; Trigger.dev handles durable
6
- * execution, retries, and concurrency.
7
- */
8
- export const onSubgraphEvent = task({
9
- id: "{{TASK_ID}}",
10
- run: async (payload: Record<string, unknown>, { ctx: _ctx }) => {
11
- console.log("[subgraph event]", payload);
12
- // TODO: your business logic — AI SDK, HTTP, DB, chain broadcasts.
13
- return { ok: true };
14
- },
15
- });
@@ -1,6 +0,0 @@
1
- import { defineConfig } from "@trigger.dev/sdk/v3";
2
-
3
- export default defineConfig({
4
- project: "{{NAME}}",
5
- dirs: ["./src/tasks"],
6
- });
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "esModuleInterop": true,
8
- "skipLibCheck": true
9
- }
10
- }