@mccaskie-labs/workbench-config 0.1.7 → 0.1.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @mccaskie-labs/workbench-config
2
2
 
3
+ ## 0.1.8
4
+
5
+ ### Patch Changes
6
+
7
+ - Database and analytics manifests use wb-probe's probe ids (`database.rls`, `database.service-reason`, `analytics.beacon`, `analytics.events`), with no smoke flags, and the checks that only the drill can see are drill probes.
8
+ - The `bin` path is written as npm normalises it (`dist/cli.js`), so publishing no longer warns about it.
9
+
3
10
  ## 0.1.7
4
11
 
5
12
  ### Patch Changes
@@ -6,29 +6,74 @@
6
6
  "summary": "Cloudflare Web Analytics counts page views through a beacon on every page; product events go into the app's own database through workbench-analytics. Apps hold no Cloudflare token: Claude reads page views through Control.",
7
7
  "status": "built",
8
8
  "surfaces": {
9
- "package": ["beaconScript", "createEvents", "eventsMigration"],
10
- "tools": ["cf_web_analytics_site_create"]
9
+ "package": [
10
+ "beaconScript",
11
+ "createEvents",
12
+ "eventsMigration"
13
+ ],
14
+ "tools": [
15
+ "cf_web_analytics_site_create"
16
+ ]
11
17
  },
12
18
  "actions": [
13
- { "tool": "cf_web_analytics_site_create", "gate": "free", "ships": "4" }
19
+ {
20
+ "tool": "cf_web_analytics_site_create",
21
+ "gate": "free",
22
+ "ships": "4"
23
+ }
14
24
  ],
15
25
  "rules": [
16
- { "id": "analytics.beacon-on-pages", "kind": "must", "text": "Put beaconScript(token) on every page, with the site's public beacon token from cf_web_analytics_site_create.", "enforced_by": "review", "probe": "analytics.beacon-present" },
17
- { "id": "analytics.track-never-throws", "kind": "must_not", "text": "Let a failed event write break the request it describes: track logs and drops it.", "enforced_by": "types", "probe": "analytics.event-round-trip" },
18
- { "id": "analytics.no-cf-token", "kind": "must_not", "text": "Hold a Cloudflare analytics token in the app (hard rule 1); page views are read with Control.", "enforced_by": "review", "probe": "analytics.page-views-drill" }
26
+ {
27
+ "id": "analytics.beacon-on-pages",
28
+ "kind": "must",
29
+ "text": "Put beaconScript(token) on every page, with the site's public beacon token from cf_web_analytics_site_create.",
30
+ "enforced_by": "review",
31
+ "probe": "analytics.beacon"
32
+ },
33
+ {
34
+ "id": "analytics.track-never-throws",
35
+ "kind": "must_not",
36
+ "text": "Let a failed event write break the request it describes: track logs and drops it.",
37
+ "enforced_by": "types",
38
+ "probe": "analytics.events"
39
+ },
40
+ {
41
+ "id": "analytics.no-cf-token",
42
+ "kind": "must_not",
43
+ "text": "Hold a Cloudflare analytics token in the app (hard rule 1); page views are read with Control.",
44
+ "enforced_by": "review",
45
+ "probe": "analytics.page-views-drill"
46
+ }
19
47
  ],
20
48
  "examples": [
21
49
  {
22
50
  "id": "analytics.example.track",
23
51
  "title": "Record a product event",
24
52
  "lang": "ts",
25
- "probe": "analytics.event-round-trip",
53
+ "probe": "analytics.events",
26
54
  "code": "import { createEvents } from '@mccaskie-labs/workbench-analytics'\n\nawait createEvents(db).track('note.created', { length: body.length }, { type: 'note', id })"
27
55
  }
28
56
  ],
29
57
  "probes": [
30
- { "id": "analytics.beacon-present", "half": "runtime", "expect": "pass", "smoke": true, "cost_hint_usd": 0 },
31
- { "id": "analytics.event-round-trip", "half": "runtime", "expect": "pass", "cost_hint_usd": 0, "note": "A product event is written and read back" },
32
- { "id": "analytics.page-views-drill", "half": "drill", "expect": "pass", "cost_hint_usd": 0, "note": "Create the site, drive page views, query them back (cf_analytics_query, later)" }
58
+ {
59
+ "id": "analytics.beacon",
60
+ "half": "runtime",
61
+ "expect": "pass",
62
+ "cost_hint_usd": 0
63
+ },
64
+ {
65
+ "id": "analytics.events",
66
+ "half": "runtime",
67
+ "expect": "pass",
68
+ "cost_hint_usd": 0,
69
+ "note": "A product event is written and read back"
70
+ },
71
+ {
72
+ "id": "analytics.page-views-drill",
73
+ "half": "drill",
74
+ "expect": "pass",
75
+ "cost_hint_usd": 0,
76
+ "note": "Create the site, drive page views, query them back (cf_analytics_query, later)"
77
+ }
33
78
  ]
34
79
  }
@@ -99,21 +99,21 @@
99
99
  "kind": "must",
100
100
  "text": "Turn on row level security for every table the publishable key can reach, so one user can't read another's rows.",
101
101
  "enforced_by": "database",
102
- "probe": "database.rls-other-user"
102
+ "probe": "database.rls"
103
103
  },
104
104
  {
105
- "id": "database.service-reason",
105
+ "id": "database.service-client-reason",
106
106
  "kind": "must",
107
107
  "text": "Give createServiceClient a reason saying why RLS is bypassed; it is logged once per isolate.",
108
108
  "enforced_by": "types",
109
- "probe": "database.service-logs-reason"
109
+ "probe": "database.service-reason"
110
110
  },
111
111
  {
112
112
  "id": "database.no-legacy-keys",
113
113
  "kind": "must_not",
114
114
  "text": "Use legacy JWT keys (anon, service_role). Only sb_publishable_ and sb_secret_ keys are accepted.",
115
115
  "enforced_by": "types",
116
- "probe": "database.config-named"
116
+ "probe": "database.crud"
117
117
  },
118
118
  {
119
119
  "id": "database.down-files",
@@ -144,28 +144,22 @@
144
144
  "id": "database.crud",
145
145
  "half": "runtime",
146
146
  "expect": "pass",
147
- "smoke": true,
148
147
  "cost_hint_usd": 0,
149
148
  "note": "Insert, read, update and delete, each timed"
150
149
  },
151
150
  {
152
- "id": "database.rls-other-user",
151
+ "id": "database.rls",
153
152
  "half": "runtime",
154
153
  "expect": "pass",
155
154
  "cost_hint_usd": 0,
156
- "note": "A second user's reads return none of the first user's rows"
155
+ "note": "A second user can't read, update or delete the first user's row"
157
156
  },
158
157
  {
159
- "id": "database.service-logs-reason",
160
- "half": "runtime",
161
- "expect": "pass",
162
- "cost_hint_usd": 0
163
- },
164
- {
165
- "id": "database.config-named",
166
- "half": "runtime",
158
+ "id": "database.service-reason",
159
+ "half": "drill",
167
160
  "expect": "pass",
168
- "cost_hint_usd": 0
161
+ "cost_hint_usd": 0,
162
+ "note": "The reason line is in the Worker's logs, which only the drill can read"
169
163
  },
170
164
  {
171
165
  "id": "database.migrations-up-down-up",
@@ -175,10 +169,10 @@
175
169
  },
176
170
  {
177
171
  "id": "database.prod-schema-check",
178
- "half": "runtime",
172
+ "half": "drill",
179
173
  "expect": "pass",
180
174
  "cost_hint_usd": 0,
181
- "note": "Manual: run npx workbench-supabase check:prod-schema in the project"
175
+ "note": "npx workbench-supabase check:prod-schema in the project's Checks"
182
176
  },
183
177
  {
184
178
  "id": "database.production-write-two-step",
@@ -1,4 +1,4 @@
1
- export declare const MANIFEST_VERSION: "012a9d08b659";
1
+ export declare const MANIFEST_VERSION: "68923c8c9776";
2
2
  export declare const capabilities: {
3
3
  readonly ai: {
4
4
  readonly $schema: "./schema.json";
@@ -158,13 +158,13 @@ export declare const capabilities: {
158
158
  readonly kind: "must";
159
159
  readonly text: "Put beaconScript(token) on every page, with the site's public beacon token from cf_web_analytics_site_create.";
160
160
  readonly enforced_by: "review";
161
- readonly probe: "analytics.beacon-present";
161
+ readonly probe: "analytics.beacon";
162
162
  }, {
163
163
  readonly id: "analytics.track-never-throws";
164
164
  readonly kind: "must_not";
165
165
  readonly text: "Let a failed event write break the request it describes: track logs and drops it.";
166
166
  readonly enforced_by: "types";
167
- readonly probe: "analytics.event-round-trip";
167
+ readonly probe: "analytics.events";
168
168
  }, {
169
169
  readonly id: "analytics.no-cf-token";
170
170
  readonly kind: "must_not";
@@ -177,16 +177,15 @@ export declare const capabilities: {
177
177
  readonly title: "Record a product event";
178
178
  readonly lang: "ts";
179
179
  readonly code: "import { createEvents } from '@mccaskie-labs/workbench-analytics'\n\nawait createEvents(db).track('note.created', { length: body.length }, { type: 'note', id })";
180
- readonly probe: "analytics.event-round-trip";
180
+ readonly probe: "analytics.events";
181
181
  }];
182
182
  readonly probes: readonly [{
183
- readonly id: "analytics.beacon-present";
183
+ readonly id: "analytics.beacon";
184
184
  readonly half: "runtime";
185
185
  readonly expect: "pass";
186
- readonly smoke: true;
187
186
  readonly cost_hint_usd: 0;
188
187
  }, {
189
- readonly id: "analytics.event-round-trip";
188
+ readonly id: "analytics.events";
190
189
  readonly half: "runtime";
191
190
  readonly expect: "pass";
192
191
  readonly cost_hint_usd: 0;
@@ -340,19 +339,19 @@ export declare const capabilities: {
340
339
  readonly kind: "must";
341
340
  readonly text: "Turn on row level security for every table the publishable key can reach, so one user can't read another's rows.";
342
341
  readonly enforced_by: "database";
343
- readonly probe: "database.rls-other-user";
342
+ readonly probe: "database.rls";
344
343
  }, {
345
- readonly id: "database.service-reason";
344
+ readonly id: "database.service-client-reason";
346
345
  readonly kind: "must";
347
346
  readonly text: "Give createServiceClient a reason saying why RLS is bypassed; it is logged once per isolate.";
348
347
  readonly enforced_by: "types";
349
- readonly probe: "database.service-logs-reason";
348
+ readonly probe: "database.service-reason";
350
349
  }, {
351
350
  readonly id: "database.no-legacy-keys";
352
351
  readonly kind: "must_not";
353
352
  readonly text: "Use legacy JWT keys (anon, service_role). Only sb_publishable_ and sb_secret_ keys are accepted.";
354
353
  readonly enforced_by: "types";
355
- readonly probe: "database.config-named";
354
+ readonly probe: "database.crud";
356
355
  }, {
357
356
  readonly id: "database.down-files";
358
357
  readonly kind: "must";
@@ -377,25 +376,20 @@ export declare const capabilities: {
377
376
  readonly id: "database.crud";
378
377
  readonly half: "runtime";
379
378
  readonly expect: "pass";
380
- readonly smoke: true;
381
379
  readonly cost_hint_usd: 0;
382
380
  readonly note: "Insert, read, update and delete, each timed";
383
381
  }, {
384
- readonly id: "database.rls-other-user";
382
+ readonly id: "database.rls";
385
383
  readonly half: "runtime";
386
384
  readonly expect: "pass";
387
385
  readonly cost_hint_usd: 0;
388
- readonly note: "A second user's reads return none of the first user's rows";
386
+ readonly note: "A second user can't read, update or delete the first user's row";
389
387
  }, {
390
- readonly id: "database.service-logs-reason";
391
- readonly half: "runtime";
392
- readonly expect: "pass";
393
- readonly cost_hint_usd: 0;
394
- }, {
395
- readonly id: "database.config-named";
396
- readonly half: "runtime";
388
+ readonly id: "database.service-reason";
389
+ readonly half: "drill";
397
390
  readonly expect: "pass";
398
391
  readonly cost_hint_usd: 0;
392
+ readonly note: "The reason line is in the Worker's logs, which only the drill can read";
399
393
  }, {
400
394
  readonly id: "database.migrations-up-down-up";
401
395
  readonly half: "drill";
@@ -403,10 +397,10 @@ export declare const capabilities: {
403
397
  readonly cost_hint_usd: 0;
404
398
  }, {
405
399
  readonly id: "database.prod-schema-check";
406
- readonly half: "runtime";
400
+ readonly half: "drill";
407
401
  readonly expect: "pass";
408
402
  readonly cost_hint_usd: 0;
409
- readonly note: "Manual: run npx workbench-supabase check:prod-schema in the project";
403
+ readonly note: "npx workbench-supabase check:prod-schema in the project's Checks";
410
404
  }, {
411
405
  readonly id: "database.production-write-two-step";
412
406
  readonly half: "drill";
@@ -1,6 +1,6 @@
1
1
  // Generated by `npm run capabilities:build` from capabilities/*.json. Do not edit.
2
2
  // check:capabilities fails in Checks when this file is stale.
3
- export const MANIFEST_VERSION = "012a9d08b659";
3
+ export const MANIFEST_VERSION = "68923c8c9776";
4
4
  export const capabilities = {
5
5
  "ai": {
6
6
  "$schema": "./schema.json",
@@ -224,14 +224,14 @@ export const capabilities = {
224
224
  "kind": "must",
225
225
  "text": "Put beaconScript(token) on every page, with the site's public beacon token from cf_web_analytics_site_create.",
226
226
  "enforced_by": "review",
227
- "probe": "analytics.beacon-present"
227
+ "probe": "analytics.beacon"
228
228
  },
229
229
  {
230
230
  "id": "analytics.track-never-throws",
231
231
  "kind": "must_not",
232
232
  "text": "Let a failed event write break the request it describes: track logs and drops it.",
233
233
  "enforced_by": "types",
234
- "probe": "analytics.event-round-trip"
234
+ "probe": "analytics.events"
235
235
  },
236
236
  {
237
237
  "id": "analytics.no-cf-token",
@@ -247,19 +247,18 @@ export const capabilities = {
247
247
  "title": "Record a product event",
248
248
  "lang": "ts",
249
249
  "code": "import { createEvents } from '@mccaskie-labs/workbench-analytics'\n\nawait createEvents(db).track('note.created', { length: body.length }, { type: 'note', id })",
250
- "probe": "analytics.event-round-trip"
250
+ "probe": "analytics.events"
251
251
  }
252
252
  ],
253
253
  "probes": [
254
254
  {
255
- "id": "analytics.beacon-present",
255
+ "id": "analytics.beacon",
256
256
  "half": "runtime",
257
257
  "expect": "pass",
258
- "smoke": true,
259
258
  "cost_hint_usd": 0
260
259
  },
261
260
  {
262
- "id": "analytics.event-round-trip",
261
+ "id": "analytics.events",
263
262
  "half": "runtime",
264
263
  "expect": "pass",
265
264
  "cost_hint_usd": 0,
@@ -486,21 +485,21 @@ export const capabilities = {
486
485
  "kind": "must",
487
486
  "text": "Turn on row level security for every table the publishable key can reach, so one user can't read another's rows.",
488
487
  "enforced_by": "database",
489
- "probe": "database.rls-other-user"
488
+ "probe": "database.rls"
490
489
  },
491
490
  {
492
- "id": "database.service-reason",
491
+ "id": "database.service-client-reason",
493
492
  "kind": "must",
494
493
  "text": "Give createServiceClient a reason saying why RLS is bypassed; it is logged once per isolate.",
495
494
  "enforced_by": "types",
496
- "probe": "database.service-logs-reason"
495
+ "probe": "database.service-reason"
497
496
  },
498
497
  {
499
498
  "id": "database.no-legacy-keys",
500
499
  "kind": "must_not",
501
500
  "text": "Use legacy JWT keys (anon, service_role). Only sb_publishable_ and sb_secret_ keys are accepted.",
502
501
  "enforced_by": "types",
503
- "probe": "database.config-named"
502
+ "probe": "database.crud"
504
503
  },
505
504
  {
506
505
  "id": "database.down-files",
@@ -531,28 +530,22 @@ export const capabilities = {
531
530
  "id": "database.crud",
532
531
  "half": "runtime",
533
532
  "expect": "pass",
534
- "smoke": true,
535
533
  "cost_hint_usd": 0,
536
534
  "note": "Insert, read, update and delete, each timed"
537
535
  },
538
536
  {
539
- "id": "database.rls-other-user",
537
+ "id": "database.rls",
540
538
  "half": "runtime",
541
539
  "expect": "pass",
542
540
  "cost_hint_usd": 0,
543
- "note": "A second user's reads return none of the first user's rows"
544
- },
545
- {
546
- "id": "database.service-logs-reason",
547
- "half": "runtime",
548
- "expect": "pass",
549
- "cost_hint_usd": 0
541
+ "note": "A second user can't read, update or delete the first user's row"
550
542
  },
551
543
  {
552
- "id": "database.config-named",
553
- "half": "runtime",
544
+ "id": "database.service-reason",
545
+ "half": "drill",
554
546
  "expect": "pass",
555
- "cost_hint_usd": 0
547
+ "cost_hint_usd": 0,
548
+ "note": "The reason line is in the Worker's logs, which only the drill can read"
556
549
  },
557
550
  {
558
551
  "id": "database.migrations-up-down-up",
@@ -562,10 +555,10 @@ export const capabilities = {
562
555
  },
563
556
  {
564
557
  "id": "database.prod-schema-check",
565
- "half": "runtime",
558
+ "half": "drill",
566
559
  "expect": "pass",
567
560
  "cost_hint_usd": 0,
568
- "note": "Manual: run npx workbench-supabase check:prod-schema in the project"
561
+ "note": "npx workbench-supabase check:prod-schema in the project's Checks"
569
562
  },
570
563
  {
571
564
  "id": "database.production-write-two-step",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mccaskie-labs/workbench-config",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Workbench app configuration: WORKBENCH_ENV, typed variables that fail by name, secrets that are never printed, and the capabilities manifest.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -22,7 +22,7 @@
22
22
  "./package.json": "./package.json"
23
23
  },
24
24
  "bin": {
25
- "workbench-config": "./dist/cli.js"
25
+ "workbench-config": "dist/cli.js"
26
26
  },
27
27
  "files": [
28
28
  "dist",