@fuzdev/fuz_app 0.95.0 → 0.97.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 (51) hide show
  1. package/dist/auth/CLAUDE.md +1 -1
  2. package/dist/auth/account_queries.d.ts +20 -5
  3. package/dist/auth/account_queries.d.ts.map +1 -1
  4. package/dist/auth/account_queries.js +21 -4
  5. package/dist/auth/bearer_auth.d.ts.map +1 -1
  6. package/dist/auth/bearer_auth.js +6 -7
  7. package/dist/auth/daemon_token_middleware.d.ts +21 -4
  8. package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
  9. package/dist/auth/daemon_token_middleware.js +61 -10
  10. package/dist/auth/middleware.d.ts.map +1 -1
  11. package/dist/auth/middleware.js +6 -2
  12. package/dist/auth/request_context.js +2 -2
  13. package/dist/db/CLAUDE.md +6 -3
  14. package/dist/db/cell_queries.js +8 -1
  15. package/dist/db/create_db.d.ts.map +1 -1
  16. package/dist/db/create_db.js +2 -14
  17. package/dist/db/db_pg.d.ts +30 -2
  18. package/dist/db/db_pg.d.ts.map +1 -1
  19. package/dist/db/db_pg.js +33 -2
  20. package/dist/db/fact_queries.d.ts.map +1 -1
  21. package/dist/http/CLAUDE.md +3 -2
  22. package/dist/http/error_schemas.d.ts +0 -6
  23. package/dist/http/error_schemas.d.ts.map +1 -1
  24. package/dist/http/error_schemas.js +0 -6
  25. package/dist/http/origin.d.ts +18 -1
  26. package/dist/http/origin.d.ts.map +1 -1
  27. package/dist/http/origin.js +17 -0
  28. package/dist/server/serve_fact_route.d.ts +12 -0
  29. package/dist/server/serve_fact_route.d.ts.map +1 -1
  30. package/dist/server/serve_fact_route.js +40 -0
  31. package/dist/testing/CLAUDE.md +23 -3
  32. package/dist/testing/audit_completeness.d.ts.map +1 -1
  33. package/dist/testing/audit_completeness.js +4 -1
  34. package/dist/testing/cross_backend/bootstrap_backend.d.ts.map +1 -1
  35. package/dist/testing/cross_backend/bootstrap_backend.js +8 -0
  36. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
  37. package/dist/testing/cross_backend/cell_crud.js +23 -0
  38. package/dist/testing/cross_backend/conformance_case.d.ts +40 -0
  39. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  40. package/dist/testing/cross_backend/conformance_case.js +34 -0
  41. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  42. package/dist/testing/cross_backend/conformance_table.js +58 -0
  43. package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
  44. package/dist/testing/cross_backend/fact_serving.js +5 -1
  45. package/dist/testing/cross_backend/setup.d.ts +17 -0
  46. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  47. package/dist/testing/cross_backend/setup.js +29 -4
  48. package/dist/testing/db.d.ts.map +1 -1
  49. package/dist/testing/db.js +6 -1
  50. package/dist/testing/middleware.js +4 -4
  51. package/package.json +6 -2
@@ -82,6 +82,15 @@ export const reconstruct_bootstrapped_handle = (serialized) => ({
82
82
  base_url: serialized.config.base_url,
83
83
  initial_cookies: serialized.keeper_cookies,
84
84
  }),
85
+ // Same cookie jar but Origin-free so the daemon-token middleware doesn't
86
+ // discard the credential as browser-context — used by the `_testing_*`
87
+ // daemon-token calls (`_testing_reset` / `_testing_schema_snapshot` /
88
+ // `_testing_action_manifest` / `_testing_mint_session`).
89
+ keeper_daemon_transport: create_fetch_transport({
90
+ base_url: serialized.config.base_url,
91
+ initial_cookies: serialized.keeper_cookies,
92
+ origin: null,
93
+ }),
85
94
  });
86
95
  /**
87
96
  * Structural subset of `SignupOutput` the runner cares about. Looser
@@ -163,7 +172,7 @@ const rpc_via_transport = async (transport, rpc_path, method, params, backend_na
163
172
  * the snapshot shapes match by design.
164
173
  */
165
174
  export const capture_schema_snapshot = async (handle, options = {}) => {
166
- const raw = await rpc_via_transport(handle.keeper_transport, handle.config.rpc_path, '_testing_schema_snapshot', { exclude_tables: [...(options.exclude_tables ?? [])] }, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
175
+ const raw = await rpc_via_transport(handle.keeper_daemon_transport, handle.config.rpc_path, '_testing_schema_snapshot', { exclude_tables: [...(options.exclude_tables ?? [])] }, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
167
176
  // TODO: cast, not parse — `SchemaSnapshot.parse(raw)` would validate the wire
168
177
  // against the schema (the `capture_action_manifest` twin parses + uses a
169
178
  // strict object); parsing here may surface a latent schema-model gap to
@@ -181,7 +190,7 @@ export const capture_schema_snapshot = async (handle, options = {}) => {
181
190
  * `fuz_testing` mirror); the normalized shapes match by design.
182
191
  */
183
192
  export const capture_action_manifest = async (handle) => {
184
- const raw = await rpc_via_transport(handle.keeper_transport, handle.config.rpc_path, '_testing_action_manifest', {}, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
193
+ const raw = await rpc_via_transport(handle.keeper_daemon_transport, handle.config.rpc_path, '_testing_action_manifest', {}, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
185
194
  return ActionManifest.parse(raw);
186
195
  };
187
196
  /**
@@ -215,7 +224,7 @@ const TestingResetResponseShape = z.object({
215
224
  * can close over them.
216
225
  */
217
226
  const fire_testing_reset = async (handle, options) => {
218
- const raw = await rpc_via_transport(handle.keeper_transport, handle.config.rpc_path, '_testing_reset', {
227
+ const raw = await rpc_via_transport(handle.keeper_daemon_transport, handle.config.rpc_path, '_testing_reset', {
219
228
  extra_keeper_roles: options.extra_keeper_roles ?? [],
220
229
  extra_accounts: (options.extra_accounts ?? []).map((spec) => ({
221
230
  username: spec.username,
@@ -387,6 +396,17 @@ const create_keeper_transport = (handle, cookie_name, session_cookie) => create_
387
396
  base_url: handle.config.base_url,
388
397
  initial_cookies: [`${cookie_name}=${session_cookie}`],
389
398
  });
399
+ /**
400
+ * Origin-free twin of `create_keeper_transport` — same fresh keeper cookie
401
+ * jar but `origin: null` so the daemon-token middleware doesn't discard the
402
+ * credential as browser-context. Used for the per-test `_testing_*`
403
+ * daemon-token calls (the rebuilt handle's `keeper_daemon_transport`).
404
+ */
405
+ const create_keeper_daemon_transport = (handle, cookie_name, session_cookie) => create_fetch_transport({
406
+ base_url: handle.config.base_url,
407
+ initial_cookies: [`${cookie_name}=${session_cookie}`],
408
+ origin: null,
409
+ });
390
410
  /**
391
411
  * Build a `SetupTest` against a spawned + bootstrapped backend.
392
412
  *
@@ -428,9 +448,14 @@ export const default_cross_process_setup = (handle, options) => {
428
448
  // `session_cookie` for any keeper-acting calls this test makes
429
449
  // (e.g. `fixture.create_account()`'s `invite_create` step).
430
450
  const keeper_transport = create_keeper_transport(handle, cookie_name, keeper.session_cookie);
451
+ // Origin-free twin for the per-test daemon-token calls — the original
452
+ // `handle.keeper_daemon_transport` carries the wiped `globalSetup` keeper
453
+ // cookie, so rebuild it against the freshly re-seeded keeper.
454
+ const keeper_daemon_transport = create_keeper_daemon_transport(handle, cookie_name, keeper.session_cookie);
431
455
  const refreshed_handle = {
432
456
  ...handle,
433
457
  keeper_transport,
458
+ keeper_daemon_transport,
434
459
  keeper_account: keeper.account,
435
460
  keeper_actor: keeper.actor,
436
461
  keeper_cookies: [`${cookie_name}=${keeper.session_cookie}`],
@@ -508,7 +533,7 @@ export const default_cross_process_setup = (handle, options) => {
508
533
  // so `_testing_mint_session` mints the backdated row + signs the
509
534
  // cookie server-side over the keeper's daemon-token channel.
510
535
  mint_expired_session: async () => {
511
- const raw = await rpc_via_transport(refreshed_handle.keeper_transport, handle.config.rpc_path, '_testing_mint_session', { account_id: keeper.account.id, expires_in_seconds: EXPIRED_SESSION_OFFSET_SECONDS }, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
536
+ const raw = await rpc_via_transport(refreshed_handle.keeper_daemon_transport, handle.config.rpc_path, '_testing_mint_session', { account_id: keeper.account.id, expires_in_seconds: EXPIRED_SESSION_OFFSET_SECONDS }, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
512
537
  const parsed = MintSessionResponseShape.safeParse(raw);
513
538
  if (!parsed.success) {
514
539
  throw new Error(`_testing_mint_session(${handle.config.name}) returned unexpected result: ` +
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/db.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA8B7B,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAKpC;;GAEG;AACH,eAAO,MAAM,KAAK,SAA4B,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,IAAI,CAGvD,CAAC;AAMF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,KAAG,SAkB7E,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EACtC,WAAW,MAAM,KACf,SA2DF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,UAQhC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,UAAyC,CAAC;AAEvF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,IAAI,CAG3D,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,GAC9B,WAAW,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,EACvC,iBAAiB,KAAK,CAAC,MAAM,CAAC,KAC5B,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,KAAK,IAAI,CAwBzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,KAAK,CAAC,SAAS,CAAC,KAAG,IAMnE,CAAC"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/db.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA8B7B,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAKpC;;GAEG;AACH,eAAO,MAAM,KAAK,SAA4B,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,IAAI,CAGvD,CAAC;AAMF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,KAAG,SAkB7E,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EACtC,WAAW,MAAM,KACf,SAgEF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,UAQhC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,UAAyC,CAAC;AAEvF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,IAAI,CAG3D,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,GAC9B,WAAW,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,EACvC,iBAAiB,KAAK,CAAC,MAAM,CAAC,KAC5B,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,KAAK,IAAI,CAwBzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,KAAK,CAAC,SAAS,CAAC,KAAG,IAMnE,CAAC"}
@@ -26,7 +26,7 @@ import { describe, beforeAll, beforeEach, afterAll } from 'vitest';
26
26
  import { to_error_message } from '@fuzdev/fuz_util/error.ts';
27
27
  import { create_pglite_db } from '../db/db_pglite.js';
28
28
  import { assert_valid_sql_identifier } from '../db/sql_identifier.js';
29
- import { create_pg_db } from '../db/db_pg.js';
29
+ import { create_pg_db, register_pg_type_parsers } from '../db/db_pg.js';
30
30
  /**
31
31
  * CI detection — `CI=true` is set automatically by GitHub Actions, GitLab CI, etc.
32
32
  */
@@ -121,6 +121,11 @@ export const create_pg_factory = (init_schema, test_url) => {
121
121
  pool_ref = null;
122
122
  }
123
123
  const { Pool } = await import('pg');
124
+ // Mirror production's int8→number coercion (`create_db`) so the
125
+ // test pg pool reads `BIGSERIAL` columns (e.g. `audit_log.seq`)
126
+ // as numbers like PGlite does — without this the pg leg of a
127
+ // `.db.test.ts` sees `seq` as a string and wire-schema parses fail.
128
+ await register_pg_type_parsers();
124
129
  const pool = new Pool({ connectionString: test_url });
125
130
  pool_ref = pool;
126
131
  const { db } = create_pg_db(pool);
@@ -13,7 +13,7 @@ import { Hono } from 'hono';
13
13
  import { Logger } from '@fuzdev/fuz_util/log.ts';
14
14
  import { create_bearer_auth_middleware } from '../auth/bearer_auth.js';
15
15
  import { query_validate_api_token } from '../auth/api_token_queries.js';
16
- import { query_account_by_id, query_actor_by_id, query_actors_by_account, } from '../auth/account_queries.js';
16
+ import { query_account_by_id, query_actor_by_id, query_active_actors_by_account, } from '../auth/account_queries.js';
17
17
  import { query_role_grant_find_active_for_actor } from '../auth/role_grant_queries.js';
18
18
  import { create_proxy_middleware } from '../http/proxy.js';
19
19
  import { get_client_ip } from '../http/client_ip.js';
@@ -29,7 +29,7 @@ vi.mock('../auth/api_token_queries.js', () => ({
29
29
  vi.mock('../auth/account_queries.js', () => ({
30
30
  query_account_by_id: vi.fn(),
31
31
  query_actor_by_id: vi.fn(),
32
- query_actors_by_account: vi.fn(),
32
+ query_active_actors_by_account: vi.fn(),
33
33
  }));
34
34
  vi.mock('../auth/role_grant_queries.js', () => ({
35
35
  query_role_grant_find_active_for_actor: vi.fn(),
@@ -52,7 +52,7 @@ export const create_bearer_auth_mocks = (tc) => {
52
52
  const mock_validate = vi.mocked(query_validate_api_token);
53
53
  const mock_find_by_id = vi.mocked(query_account_by_id);
54
54
  const mock_find_actor_by_id = vi.mocked(query_actor_by_id);
55
- const mock_find_actors_by_account = vi.mocked(query_actors_by_account);
55
+ const mock_find_actors_by_account = vi.mocked(query_active_actors_by_account);
56
56
  const mock_find_active_for_actor = vi.mocked(query_role_grant_find_active_for_actor);
57
57
  mock_validate
58
58
  .mockReset()
@@ -211,7 +211,7 @@ export const create_test_middleware_stack_app = (options) => {
211
211
  const mock_validate = vi.mocked(query_validate_api_token);
212
212
  const mock_find_by_id = vi.mocked(query_account_by_id);
213
213
  const mock_find_actor_by_id = vi.mocked(query_actor_by_id);
214
- const mock_find_actors_by_account = vi.mocked(query_actors_by_account);
214
+ const mock_find_actors_by_account = vi.mocked(query_active_actors_by_account);
215
215
  const mock_find_active_for_actor = vi.mocked(query_role_grant_find_active_for_actor);
216
216
  mock_validate.mockReset().mockImplementation(() => Promise.resolve(undefined));
217
217
  mock_find_by_id.mockReset().mockImplementation(() => Promise.resolve(undefined));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.95.0",
3
+ "version": "0.97.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",
@@ -23,6 +23,10 @@
23
23
  "deploy": "gro deploy"
24
24
  },
25
25
  "type": "module",
26
+ "imports": {
27
+ "#lib/*": "./src/lib/*",
28
+ "#routes/*": "./src/routes/*"
29
+ },
26
30
  "engines": {
27
31
  "node": ">=24.14"
28
32
  },
@@ -79,7 +83,7 @@
79
83
  "@hono/node-server": "^1.19.14",
80
84
  "@hono/node-ws": "^1.3.1",
81
85
  "@node-rs/argon2": "^2.0.2",
82
- "@ryanatkn/eslint-config": "^0.12.1",
86
+ "@ryanatkn/eslint-config": "^0.12.2",
83
87
  "@sveltejs/acorn-typescript": "^1.0.9",
84
88
  "@sveltejs/adapter-static": "^3.0.10",
85
89
  "@sveltejs/kit": "^2.63.0",