@fuzdev/fuz_app 0.142.0 → 0.144.0

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.
Files changed (63) hide show
  1. package/dist/auth/CLAUDE.md +8 -0
  2. package/dist/auth/cell_action_specs.d.ts +13 -0
  3. package/dist/auth/cell_action_specs.d.ts.map +1 -1
  4. package/dist/auth/cell_action_specs.js +13 -0
  5. package/dist/auth/cell_actions.d.ts +7 -0
  6. package/dist/auth/cell_actions.d.ts.map +1 -1
  7. package/dist/auth/cell_actions.js +30 -0
  8. package/dist/auth/cell_ref_admission.d.ts +51 -0
  9. package/dist/auth/cell_ref_admission.d.ts.map +1 -0
  10. package/dist/auth/cell_ref_admission.js +69 -0
  11. package/dist/auth/deps.d.ts +6 -3
  12. package/dist/auth/deps.d.ts.map +1 -1
  13. package/dist/db/CLAUDE.md +34 -21
  14. package/dist/db/cell_ddl.d.ts +3 -2
  15. package/dist/db/cell_ddl.d.ts.map +1 -1
  16. package/dist/db/cell_ddl.js +3 -2
  17. package/dist/db/cell_queries.d.ts +31 -6
  18. package/dist/db/cell_queries.d.ts.map +1 -1
  19. package/dist/db/cell_queries.js +45 -18
  20. package/dist/db/fact_ddl.d.ts +29 -4
  21. package/dist/db/fact_ddl.d.ts.map +1 -1
  22. package/dist/db/fact_ddl.js +43 -4
  23. package/dist/db/fact_holder_queries.d.ts +66 -0
  24. package/dist/db/fact_holder_queries.d.ts.map +1 -0
  25. package/dist/db/fact_holder_queries.js +75 -0
  26. package/dist/db/fact_queries.d.ts +9 -7
  27. package/dist/db/fact_queries.d.ts.map +1 -1
  28. package/dist/db/fact_store.d.ts +65 -9
  29. package/dist/db/fact_store.d.ts.map +1 -1
  30. package/dist/db/fact_store.js +49 -20
  31. package/dist/http/CLAUDE.md +1 -1
  32. package/dist/http/ip_canonical.d.ts +26 -2
  33. package/dist/http/ip_canonical.d.ts.map +1 -1
  34. package/dist/http/ip_canonical.js +107 -42
  35. package/dist/server/serve_fact_route.d.ts +24 -4
  36. package/dist/server/serve_fact_route.d.ts.map +1 -1
  37. package/dist/server/serve_fact_route.js +24 -4
  38. package/dist/testing/CLAUDE.md +31 -5
  39. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
  40. package/dist/testing/cross_backend/cell_crud.js +6 -3
  41. package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
  42. package/dist/testing/cross_backend/cell_gated_create.js +25 -16
  43. package/dist/testing/cross_backend/cell_ref_admission.d.ts +4 -0
  44. package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -0
  45. package/dist/testing/cross_backend/cell_ref_admission.js +268 -0
  46. package/dist/testing/cross_backend/expected_schema.json +66 -10
  47. package/dist/testing/cross_backend/fact_serving.d.ts +19 -1
  48. package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
  49. package/dist/testing/cross_backend/fact_serving.js +31 -9
  50. package/dist/testing/cross_backend/full_spine_mount.js +2 -1
  51. package/dist/testing/cross_backend/origin_conformance.d.ts +1 -1
  52. package/dist/testing/cross_backend/origin_conformance.d.ts.map +1 -1
  53. package/dist/testing/cross_backend/origin_conformance.js +1 -1
  54. package/dist/testing/cross_backend/spine_surface_constants.d.ts +12 -20
  55. package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
  56. package/dist/testing/cross_backend/spine_surface_constants.js +12 -20
  57. package/dist/testing/cross_backend/testing_origin_check.d.ts +128 -0
  58. package/dist/testing/cross_backend/testing_origin_check.d.ts.map +1 -0
  59. package/dist/testing/cross_backend/testing_origin_check.js +87 -0
  60. package/dist/testing/cross_backend/testing_reset_actions.d.ts +13 -121
  61. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  62. package/dist/testing/cross_backend/testing_reset_actions.js +21 -95
  63. package/package.json +1 -1
@@ -15,17 +15,17 @@ import '../assert_dev_env.js';
15
15
  * of notifications onto the caller's own WebSocket connection, to push its
16
16
  * outbound queue past its byte budget).
17
17
  *
18
- * Three further daemon-token actions live here but are **not** bundled by
18
+ * Two further daemon-token actions live here but are **not** bundled by
19
19
  * `create_testing_actions`, and are appended at the full-mount layer
20
20
  * (`build_full_spine_rpc_actions`) instead: **`_testing_action_manifest`**
21
21
  * (dump the live RPC registry for cross-impl method-set + auth-shape parity —
22
22
  * it must enumerate *every* mounted method, so it goes where the complete list
23
- * exists), **`_testing_origin_check`** (answer the origin allowlist's parse
24
- * and request check for the cross-impl origin conformance table), and
25
- * **`_testing_shorten_credential_expiry`** (pull an account's credential
26
- * expiries in to seconds from now, shorten-only, for the credential-deadline
27
- * cases) — the last two kept out of the bundle so a consumer whose Rust binary
28
- * doesn't mount their mirrors keeps a green manifest gate.
23
+ * exists) and **`_testing_shorten_credential_expiry`** (pull an account's
24
+ * credential expiries in to seconds from now, shorten-only, for the
25
+ * credential-deadline cases) — the latter kept out of the bundle so a consumer
26
+ * whose Rust binary doesn't mount its mirror keeps a green manifest gate.
27
+ * `_testing_origin_check`, mounted the same way, lives in the hono-free
28
+ * `testing_origin_check.ts`.
29
29
  *
30
30
  * `_testing_reset` — full DB wipe + keeper re-seed + optional
31
31
  * secondary-account seeding. The
@@ -83,27 +83,14 @@ import { jsonrpc_errors } from '../../http/jsonrpc_errors.js';
83
83
  import { emit_after_commit } from '../../http/pending_effects.js';
84
84
  import { protocol_action_specs } from '../../actions/protocol.js';
85
85
  import { query_put_fact } from '../../db/fact_queries.js';
86
+ import { query_put_fact_holder } from '../../db/fact_holder_queries.js';
86
87
  import { ROLE_ADMIN, ROLE_KEEPER } from '../../auth/role_schema.js';
87
88
  import { query_schema_snapshot, SchemaSnapshot, query_migration_tracker, MigrationTracker } from '../schema_introspect.js';
88
89
  import { ActionManifest, build_action_manifest } from './action_manifest.js';
89
90
  import { query_create_actor } from '../../auth/account_queries.js';
90
91
  import { create_test_account_with_credentials, mint_test_session } from '../app_server.js';
91
92
  import { DEFAULT_TEST_PASSWORD } from '../test_credentials.js';
92
- import { AllowedOriginsErrorKind, parse_allowed_origins, should_allow_origin } from '../../http/origin.js';
93
- /**
94
- * Shared `auth` axis for every `_testing_*` action: keeper-only via the
95
- * daemon-token credential, no acting actor. This is the entire structural
96
- * fence on the backdoor surface (these actions run direct DB writes the
97
- * production wire never exposes), so every `_testing_*` spec references this
98
- * one const rather than re-declaring it — a single source of truth the gate test
99
- * (`testing_actions_auth.test.ts`) pins. Mirrors the Rust `DAEMON_TOKEN_ONLY`
100
- * / shared `AuthSpec` in `fuz_testing`.
101
- */
102
- const TESTING_ACTION_AUTH = {
103
- account: 'required',
104
- actor: 'none',
105
- credential_types: ['daemon_token']
106
- };
93
+ import { TESTING_ACTION_AUTH } from './spine_surface_constants.js';
107
94
  /** Output shape for an individual seeded account (keeper or extra). */
108
95
  const SeededAccountShape = z.strictObject({
109
96
  account: z.strictObject({ id: Uuid, username: z.string() }),
@@ -276,8 +263,11 @@ export const create_testing_drain_effects_action = (audit) => rpc_action(testing
276
263
  * cross-process fact-serving suite, which drives over real HTTP and has no
277
264
  * `PgFactStore` to call. Hashes the UTF-8 `content` (blake3, via
278
265
  * `fact_hash_bytes` — the same hash the Rust `_testing_put_fact` computes),
279
- * inserts the row idempotently, and returns `{hash}`. The referencing cell is
280
- * seeded separately via the `cell_create` RPC. Embedded-only is enough for the
266
+ * inserts the row idempotently, and returns `{hash}`. `holder` names the actor
267
+ * the put is on behalf of — recorded in `fact_holder` (deduplicated puts
268
+ * included), as a real upload records its uploader, so the suites can drive
269
+ * cell ref admission; absent, the put is a system put with no holder. The
270
+ * referencing cell is seeded separately via the `cell_create` RPC. Embedded-only is enough for the
281
271
  * authz assertions (cell-scoped admit, cross-owner-no-leak, 404-mask, bare-hash
282
272
  * admin-only); external / X-Accel parity stays covered by the forge's own gate.
283
273
  *
@@ -293,7 +283,8 @@ export const testing_put_fact_action_spec = {
293
283
  side_effects: true,
294
284
  input: z.strictObject({
295
285
  content: z.string(),
296
- content_type: z.string().optional()
286
+ content_type: z.string().optional(),
287
+ holder: Uuid.optional()
297
288
  }),
298
289
  output: z.strictObject({ hash: FactHashSchema }),
299
290
  async: true,
@@ -459,76 +450,6 @@ export const testing_migration_tracker_action_spec = {
459
450
  * `create_testing_actions`; mount directly for in-process use.
460
451
  */
461
452
  export const create_testing_migration_tracker_action = () => rpc_action(testing_migration_tracker_action_spec, async (_input, ctx) => query_migration_tracker(ctx.db));
462
- /** Input of `_testing_origin_check`. */
463
- export const TestingOriginCheckInput = z.strictObject({
464
- /** An allowlist value, as `FUZ_ALLOWED_ORIGINS` would carry it. */
465
- patterns: z.string(),
466
- /** One `Origin` header's value, or `null` for a request without one. */
467
- origin: z.string().nullable()
468
- });
469
- /**
470
- * Output of `_testing_origin_check`: the request-level answer when the list
471
- * parses, else every refusal — `index` the 1-based entry position, absent for
472
- * a list-level refusal.
473
- */
474
- export const TestingOriginCheckOutput = z.union([
475
- z.strictObject({ ok: z.literal(true), allowed: z.boolean() }),
476
- z.strictObject({
477
- ok: z.literal(false),
478
- errors: z.array(z.strictObject({ index: z.number().int().min(1).optional(), kind: AllowedOriginsErrorKind }))
479
- })
480
- ]);
481
- /**
482
- * Answer one `_testing_origin_check` input: parse `patterns` with
483
- * `parse_allowed_origins`, then run the request-level check for one `Origin`
484
- * carrying `origin` (`null` — no `Origin` — passes). The action handler and
485
- * the conformance table's unit test both call this, so the table checks the
486
- * same function the wire serves.
487
- *
488
- * @param input - the allowlist value and the `Origin` value
489
- * @returns the answer the Rust twin returns for the same input
490
- */
491
- export const run_testing_origin_check = (input) => {
492
- const parsed = parse_allowed_origins(input.patterns);
493
- if (!parsed.ok) {
494
- return {
495
- ok: false,
496
- errors: parsed.errors.map(({ index, kind }) => index === undefined ? { kind } : { index, kind })
497
- };
498
- }
499
- return {
500
- ok: true,
501
- allowed: input.origin === null || should_allow_origin(input.origin, parsed.origins)
502
- };
503
- };
504
- /**
505
- * `_testing_origin_check` — run the origin allowlist's parse and request
506
- * check for one `{patterns, origin}` pair, so the shared conformance table
507
- * (`origin_conformance.json`) checks each backend's grammar and matcher over
508
- * the wire, row by row. Pure: no database, no state. The Rust mirror is
509
- * `fuz_testing::create_testing_origin_check_action_spec`.
510
- *
511
- * Like `_testing_action_manifest`, it is **not** bundled by
512
- * `create_testing_actions`: a consumer whose Rust binary doesn't mount the
513
- * mirror would fail its action-manifest parity gate. The spine test binary
514
- * appends it at the full-mount layer (`build_full_spine_rpc_actions`).
515
- *
516
- * `auth` gates on the daemon-token credential, matching `_testing_reset`.
517
- */
518
- export const testing_origin_check_action_spec = {
519
- method: '_testing_origin_check',
520
- kind: 'request_response',
521
- initiator: 'frontend',
522
- auth: TESTING_ACTION_AUTH,
523
- side_effects: false,
524
- input: TestingOriginCheckInput,
525
- output: TestingOriginCheckOutput,
526
- async: true,
527
- description: "Test-binary only — answer the origin allowlist's parse and request check for one " +
528
- '{patterns, origin} pair, for the cross-impl origin conformance table.'
529
- };
530
- /** Build the standalone `_testing_origin_check` action (see the spec doc). */
531
- export const create_testing_origin_check_action = () => rpc_action(testing_origin_check_action_spec, async (input) => run_testing_origin_check(input));
532
453
  /** The shortest expiry `_testing_shorten_credential_expiry` sets, in seconds from now. */
533
454
  export const TESTING_SHORTEN_CREDENTIAL_EXPIRY_MIN_SECONDS = 1;
534
455
  /**
@@ -803,6 +724,11 @@ export const create_testing_actions = (deps, options) => {
803
724
  content_type: input.content_type ?? null,
804
725
  size: bytes.length
805
726
  });
727
+ // the holder row, on a dedup hit too (`PgFactStore`'s put records it the
728
+ // same way); an unknown actor fails the FK
729
+ if (input.holder !== undefined) {
730
+ await query_put_fact_holder({ db: ctx.db }, input.holder, hash);
731
+ }
806
732
  return { hash };
807
733
  }),
808
734
  create_testing_drain_effects_action(deps.audit),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.142.0",
3
+ "version": "0.144.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",