@fuzdev/fuz_app 0.41.1 → 0.43.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.
@@ -1 +1 @@
1
- {"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE9F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,OAAO,EAGN,KAAK,gBAAgB,EAGrB,MAAM,oBAAoB,CAAC;AAW5B;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,+DAA+D;IAC/D,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,EAAE,CAAC;IACP,oFAAoF;IACpF,aAAa,EAAE,EAAE,CAAC;IAClB,2EAA2E;IAC3E,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,CACxD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,aAAa,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,yBAAyB,EACjE,MAAM,KAAK,EACX,SAAS,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KACvE,SAGD,CAAC;AAEH,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACxC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;CACZ;AA4DD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,wBAAwB,KAAG,KAAK,CAAC,SAAS,CA6PtF,CAAC"}
1
+ {"version":3,"file":"action_rpc.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/action_rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAgC,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE9F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,OAAO,EAGN,KAAK,gBAAgB,EAGrB,MAAM,oBAAoB,CAAC;AAW5B;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,+DAA+D;IAC/D,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,EAAE,CAAC;IACP,oFAAoF;IACpF,aAAa,EAAE,EAAE,CAAC;IAClB,2EAA2E;IAC3E,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,CACxD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,aAAa,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,yBAAyB,CAAC;IAChC,OAAO,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,yBAAyB,EACjE,MAAM,KAAK,EACX,SAAS,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KACvE,SAGD,CAAC;AAEH,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACxC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;CACZ;AA4DD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,wBAAwB,KAAG,KAAK,CAAC,SAAS,CAsQtF,CAAC"}
@@ -17,7 +17,7 @@ import {} from '../http/route_spec.js';
17
17
  import { get_client_ip } from '../http/proxy.js';
18
18
  import { get_request_context, has_role } from '../auth/request_context.js';
19
19
  import { CREDENTIAL_TYPE_KEY } from '../hono_context.js';
20
- import { is_null_schema } from '../http/schema_helpers.js';
20
+ import { is_null_schema, is_void_schema } from '../http/schema_helpers.js';
21
21
  import { JSONRPC_VERSION, JsonrpcRequest, } from '../http/jsonrpc.js';
22
22
  import { jsonrpc_error_messages, jsonrpc_error_code_to_http_status, JSONRPC_ERROR_CODES, } from '../http/jsonrpc_errors.js';
23
23
  import { ERROR_INSUFFICIENT_PERMISSIONS, ERROR_KEEPER_REQUIRES_DAEMON_TOKEN, } from '../http/error_schemas.js';
@@ -127,6 +127,9 @@ export const create_rpc_endpoint = (options) => {
127
127
  if (action_map.has(action.spec.method)) {
128
128
  throw new Error(`Duplicate RPC action method: ${action.spec.method}`);
129
129
  }
130
+ if (is_null_schema(action.spec.input)) {
131
+ throw new Error(`RPC action "${action.spec.method}" uses z.null() for input — JSON-RPC 2.0 §4.2 forbids "params": null on the wire (must be omitted or be a Structured value). Use z.void() for parameterless methods.`);
132
+ }
130
133
  action_map.set(action.spec.method, action);
131
134
  }
132
135
  /**
@@ -163,12 +166,16 @@ export const create_rpc_endpoint = (options) => {
163
166
  return c.json(error, jsonrpc_error_code_to_http_status(auth_error.code));
164
167
  }
165
168
  // step 4: validate params
166
- // Missing `params` on the envelope maps to `null` for `z.null()` input
167
- // schemas and `{}` for object inputs matches HTTP's "empty body = empty
168
- // object" convention so callers of all-optional-object RPC methods can
169
- // omit `params` on the wire (JSON-RPC envelope still serializes without
170
- // a `params` field; no protocol-level change).
171
- const params = raw_params ?? (is_null_schema(action.spec.input) ? null : {});
169
+ // Missing `params` on the envelope maps to `undefined` for `z.void()`
170
+ // input schemas and `{}` for object inputs (matches HTTP's "empty
171
+ // body = empty object" convention so callers of all-optional-object
172
+ // RPC methods can omit `params` on the wire). JSON-RPC 2.0 §4.2
173
+ // forbids `params: null`, so `z.void()` is the spec-correct schema
174
+ // for parameterless methods registration above rejects `z.null()`
175
+ // inputs to keep this branch from having to consider that legacy
176
+ // shape. When `raw_params` is present it flows through unchanged so
177
+ // contract-violating shapes still fail validation.
178
+ const params = is_void_schema(action.spec.input) ? raw_params : (raw_params ?? {});
172
179
  const parse_result = action.spec.input.safeParse(params);
173
180
  if (!parse_result.success) {
174
181
  const error = jsonrpc_error_response(id, jsonrpc_error_messages.invalid_params('invalid params', {
@@ -513,9 +513,96 @@ run'` if the seed somehow missed (defensive — migrations always seed).
513
513
  `permit_actor_role_active_unique` and installs scope-aware
514
514
  `permit_actor_role_scope_active_unique` using the
515
515
  `PERMIT_OFFER_SCOPE_SENTINEL_UUID`.
516
- - Forward-only (no down). Named migrations are preferred so the name
516
+ - Forward-only (no down). Migrations are `{name, up}` objects; the name
517
517
  surfaces in error messages.
518
518
 
519
+ #### Runner contract (`db/migrate.ts`)
520
+
521
+ The `schema_version` table stores **one row per applied migration**, keyed
522
+ by `(namespace, name)` with a monotonically-increasing per-namespace
523
+ `sequence` and `applied_at`. `run_migrations` reads applied rows ordered
524
+ by `sequence`, then enforces:
525
+
526
+ 1. **Length check first.** If `applied.length > code.length`, throw
527
+ `binary-older-than-db` listing the unknown names. Short-circuits
528
+ before name verify so a binary-older case with a rename in the overlap
529
+ doesn't fire `name-divergence-at-N` first and send the operator chasing
530
+ a phantom source-revert.
531
+ 2. **Name-prefix verify.** For each `i < applied.length`, assert
532
+ `applied[i].name === code[i].name`; mismatch throws
533
+ `name-divergence-at-N` with `at_index`.
534
+ 3. **Run the pending tail** (`code[applied.length..]`) inside a single
535
+ chain transaction; each `INSERT` uses `sequence = max(sequence) + 1`.
536
+
537
+ **Append-only after first publish.** Once a fuz_app version containing a
538
+ migration is published, the migration's name and position are frozen.
539
+ Pre-publish, anything goes; the cliff is the publish event. Body edits to
540
+ a published migration slip past the runner (no content hashing) — schema-
541
+ snapshot tests in consumers catch these.
542
+
543
+ `MigrationError` is the only error class thrown from `run_migrations` /
544
+ `baseline`; branch on `.kind` (never on message text). Kinds:
545
+ `binary-older-than-db`, `name-divergence-at-N`, `old-tracker-shape`,
546
+ `migration-failed`, `baseline-name-not-in-code`,
547
+ `baseline-name-out-of-order`, `baseline-namespace-already-populated`.
548
+
549
+ `baseline(db, ns, names)` is the only sanctioned non-execution path —
550
+ INSERTs tracker rows for a name-prefix of `ns.migrations` without running
551
+ their `up` functions. Used to promote an existing schema (e.g. preserved
552
+ through a tracker-shape upgrade) into the new tracker. Per-namespace
553
+ populated guard lets multi-call cutover scripts resume after partial
554
+ failure. `baseline()` does **not** verify the schema actually matches
555
+ what the named migrations would have produced — pair with a
556
+ schema-assertion script post-baseline.
557
+
558
+ There is **no programmatic bypass on the main `run_migrations` path**.
559
+ No `--force`, no `skip_verification`. If you need to deviate, reach for
560
+ `baseline()` (named, narrow) or direct SQL on the tracker (operator
561
+ explicitly states intent).
562
+
563
+ #### Operator recipes (run with the service stopped — these bypass the advisory lock)
564
+
565
+ **Rename a migration** (typo fix, etc.). This is a coordinated code+SQL
566
+ change, not just SQL:
567
+
568
+ 1. Stop the service. Disable auto-restart for the cutover window.
569
+ 2. Run the SQL `UPDATE` first — old code on disk doesn't read `name`, so
570
+ running this with the old build still deployed is harmless and the
571
+ safer order.
572
+ 3. Deploy the build with the renamed migration in the code array.
573
+ 4. Start the service — boot's name-prefix verify passes.
574
+
575
+ The bad order is "deploy code with new name, then SQL UPDATE" — boot
576
+ fires `name-divergence-at-N` and refuses to start in between.
577
+
578
+ ```sql
579
+ UPDATE schema_version SET name = 'new_name'
580
+ WHERE namespace = $ns AND name = 'old_name';
581
+ ```
582
+
583
+ **Mark a single migration applied without running it** (extreme repair —
584
+ prefer `baseline()` when promoting a whole prefix):
585
+
586
+ ```sql
587
+ INSERT INTO schema_version (namespace, name, sequence, applied_at)
588
+ VALUES ($ns, $name,
589
+ (SELECT COALESCE(MAX(sequence), -1) + 1
590
+ FROM schema_version WHERE namespace = $ns),
591
+ NOW());
592
+ ```
593
+
594
+ **Reset a namespace** (drop tracker rows; idempotent migrations re-apply
595
+ on next boot):
596
+
597
+ ```sql
598
+ DELETE FROM schema_version WHERE namespace = $ns;
599
+ ```
600
+
601
+ A `set_applied()` / `rename_applied()` helper was considered and
602
+ rejected — even one sanctioned bypass that doesn't name the operator's
603
+ intent invites use as a regular tool. Direct SQL forces the operator to
604
+ consciously violate the contract.
605
+
519
606
  ## Middleware
520
607
 
521
608
  Side of the chain ordering (concept-level — see the root `../../../CLAUDE.md`
@@ -758,16 +845,16 @@ auth per-spec, so mixed-auth endpoints compose cleanly.
758
845
 
759
846
  | Spec | Side effects | Input | Output |
760
847
  | -------------------------------------- | ------------ | --------------------------------------------------------- | ----------------------------- |
761
- | `admin_account_list_action_spec` | false | `z.null()` | `{accounts, grantable_roles}` |
762
- | `admin_session_list_action_spec` | false | `z.null()` | `{sessions}` |
848
+ | `admin_account_list_action_spec` | false | `z.void()` | `{accounts, grantable_roles}` |
849
+ | `admin_session_list_action_spec` | false | `z.void()` | `{sessions}` |
763
850
  | `admin_session_revoke_all_action_spec` | true | `{account_id}` | `{ok, count}` |
764
851
  | `admin_token_revoke_all_action_spec` | true | `{account_id}` | `{ok, count}` |
765
852
  | `audit_log_list_action_spec` | false | `{event_type?, account_id?, limit?, offset?, since_seq?}` | `{events}` |
766
853
  | `audit_log_permit_history_action_spec` | false | `{limit?, offset?}` | `{events}` |
767
854
  | `invite_create_action_spec` | true | `{email?, username?}` | `{ok, invite}` |
768
- | `invite_list_action_spec` | false | `z.null()` | `{invites}` |
855
+ | `invite_list_action_spec` | false | `z.void()` | `{invites}` |
769
856
  | `invite_delete_action_spec` | true | `{invite_id}` | `{ok}` |
770
- | `app_settings_get_action_spec` | false | `z.null()` | `{settings}` |
857
+ | `app_settings_get_action_spec` | false | `z.void()` | `{settings}` |
771
858
  | `app_settings_update_action_spec` | true | `{open_signup}` | `{ok, settings}` |
772
859
 
773
860
  `AUDIT_LOG_LIST_LIMIT_MAX = 200` — page size clamp (mirrors the former REST
@@ -971,12 +1058,12 @@ exists.
971
1058
 
972
1059
  | Spec | Side effects | Input | Output |
973
1060
  | ---------------------------------------- | ------------ | -------------- | ----------------------- |
974
- | `account_verify_action_spec` | false | `z.null()` | `SessionAccountJson` |
975
- | `account_session_list_action_spec` | false | `z.null()` | `{sessions}` |
1061
+ | `account_verify_action_spec` | false | `z.void()` | `SessionAccountJson` |
1062
+ | `account_session_list_action_spec` | false | `z.void()` | `{sessions}` |
976
1063
  | `account_session_revoke_action_spec` | true | `{session_id}` | `{ok, revoked}` |
977
- | `account_session_revoke_all_action_spec` | true | `z.null()` | `{ok, count}` |
1064
+ | `account_session_revoke_all_action_spec` | true | `z.void()` | `{ok, count}` |
978
1065
  | `account_token_create_action_spec` | true | `{name?}` | `{ok, token, id, name}` |
979
- | `account_token_list_action_spec` | false | `z.null()` | `{tokens}` |
1066
+ | `account_token_list_action_spec` | false | `z.void()` | `{tokens}` |
980
1067
  | `account_token_revoke_action_spec` | true | `{token_id}` | `{ok, revoked}` |
981
1068
 
982
1069
  `session_id` validates as `Blake3Hash`; `token_id` validates as
@@ -10,10 +10,10 @@
10
10
  import { z } from 'zod';
11
11
  import type { RequestResponseActionSpec } from '../actions/action_spec.js';
12
12
  /** Input for `account_verify`. No parameters — the caller is the subject. */
13
- export declare const VerifyInput: z.ZodNull;
13
+ export declare const VerifyInput: z.ZodVoid;
14
14
  export type VerifyInput = z.infer<typeof VerifyInput>;
15
15
  /** Input for `account_session_list`. No parameters. */
16
- export declare const SessionListInput: z.ZodNull;
16
+ export declare const SessionListInput: z.ZodVoid;
17
17
  export type SessionListInput = z.infer<typeof SessionListInput>;
18
18
  /** Output for `account_session_list`. */
19
19
  export declare const SessionListOutput: z.ZodObject<{
@@ -38,7 +38,7 @@ export declare const SessionRevokeOutput: z.ZodObject<{
38
38
  }, z.core.$strict>;
39
39
  export type SessionRevokeOutput = z.infer<typeof SessionRevokeOutput>;
40
40
  /** Input for `account_session_revoke_all`. No parameters. */
41
- export declare const SessionRevokeAllInput: z.ZodNull;
41
+ export declare const SessionRevokeAllInput: z.ZodVoid;
42
42
  export type SessionRevokeAllInput = z.infer<typeof SessionRevokeAllInput>;
43
43
  /** Output for `account_session_revoke_all`. */
44
44
  export declare const SessionRevokeAllOutput: z.ZodObject<{
@@ -60,7 +60,7 @@ export declare const TokenCreateOutput: z.ZodObject<{
60
60
  }, z.core.$strict>;
61
61
  export type TokenCreateOutput = z.infer<typeof TokenCreateOutput>;
62
62
  /** Input for `account_token_list`. No parameters. */
63
- export declare const TokenListInput: z.ZodNull;
63
+ export declare const TokenListInput: z.ZodVoid;
64
64
  export type TokenListInput = z.infer<typeof TokenListInput>;
65
65
  /** Output for `account_token_list`. Hashes are excluded. */
66
66
  export declare const TokenListOutput: z.ZodObject<{
@@ -92,7 +92,7 @@ export declare const account_verify_action_spec: {
92
92
  initiator: "frontend";
93
93
  auth: "authenticated";
94
94
  side_effects: false;
95
- input: z.ZodNull;
95
+ input: z.ZodVoid;
96
96
  output: z.ZodObject<{
97
97
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
98
98
  username: z.ZodString;
@@ -109,7 +109,7 @@ export declare const account_session_list_action_spec: {
109
109
  initiator: "frontend";
110
110
  auth: "authenticated";
111
111
  side_effects: false;
112
- input: z.ZodNull;
112
+ input: z.ZodVoid;
113
113
  output: z.ZodObject<{
114
114
  sessions: z.ZodArray<z.ZodObject<{
115
115
  id: z.ZodString;
@@ -144,7 +144,7 @@ export declare const account_session_revoke_all_action_spec: {
144
144
  initiator: "frontend";
145
145
  auth: "authenticated";
146
146
  side_effects: true;
147
- input: z.ZodNull;
147
+ input: z.ZodVoid;
148
148
  output: z.ZodObject<{
149
149
  ok: z.ZodLiteral<true>;
150
150
  count: z.ZodNumber;
@@ -176,7 +176,7 @@ export declare const account_token_list_action_spec: {
176
176
  initiator: "frontend";
177
177
  auth: "authenticated";
178
178
  side_effects: false;
179
- input: z.ZodNull;
179
+ input: z.ZodVoid;
180
180
  output: z.ZodObject<{
181
181
  tokens: z.ZodArray<z.ZodObject<{
182
182
  id: z.ZodString;
@@ -13,9 +13,9 @@ import { AuthSessionJson, ClientApiTokenJson, SessionAccountJson } from './accou
13
13
  import { ApiTokenId } from './api_token.js';
14
14
  // -- Input/output schemas ---------------------------------------------------
15
15
  /** Input for `account_verify`. No parameters — the caller is the subject. */
16
- export const VerifyInput = z.null();
16
+ export const VerifyInput = z.void();
17
17
  /** Input for `account_session_list`. No parameters. */
18
- export const SessionListInput = z.null();
18
+ export const SessionListInput = z.void();
19
19
  /** Output for `account_session_list`. */
20
20
  export const SessionListOutput = z.strictObject({
21
21
  sessions: z.array(AuthSessionJson),
@@ -30,7 +30,7 @@ export const SessionRevokeOutput = z.strictObject({
30
30
  revoked: z.boolean(),
31
31
  });
32
32
  /** Input for `account_session_revoke_all`. No parameters. */
33
- export const SessionRevokeAllInput = z.null();
33
+ export const SessionRevokeAllInput = z.void();
34
34
  /** Output for `account_session_revoke_all`. */
35
35
  export const SessionRevokeAllOutput = z.strictObject({
36
36
  ok: z.literal(true),
@@ -51,7 +51,7 @@ export const TokenCreateOutput = z.strictObject({
51
51
  name: z.string(),
52
52
  });
53
53
  /** Input for `account_token_list`. No parameters. */
54
- export const TokenListInput = z.null();
54
+ export const TokenListInput = z.void();
55
55
  /** Output for `account_token_list`. Hashes are excluded. */
56
56
  export const TokenListOutput = z.strictObject({
57
57
  tokens: z.array(ClientApiTokenJson),
@@ -20,7 +20,7 @@ import type { RequestResponseActionSpec } from '../actions/action_spec.js';
20
20
  /** Max audit-log page size. Mirrors the former REST route's clamp. */
21
21
  export declare const AUDIT_LOG_LIST_LIMIT_MAX = 200;
22
22
  /** Input for `admin_account_list`. No parameters — the caller is the subject. */
23
- export declare const AdminAccountListInput: z.ZodNull;
23
+ export declare const AdminAccountListInput: z.ZodVoid;
24
24
  export type AdminAccountListInput = z.infer<typeof AdminAccountListInput>;
25
25
  /** Output for `admin_account_list`. */
26
26
  export declare const AdminAccountListOutput: z.ZodObject<{
@@ -60,7 +60,7 @@ export declare const AdminAccountListOutput: z.ZodObject<{
60
60
  }, z.core.$strict>;
61
61
  export type AdminAccountListOutput = z.infer<typeof AdminAccountListOutput>;
62
62
  /** Input for `admin_session_list`. No parameters — reads every active session. */
63
- export declare const AdminSessionListInput: z.ZodNull;
63
+ export declare const AdminSessionListInput: z.ZodVoid;
64
64
  export type AdminSessionListInput = z.infer<typeof AdminSessionListInput>;
65
65
  /** Output for `admin_session_list`. Cross-account listing; fan-out already scoped by role auth. */
66
66
  export declare const AdminSessionListOutput: z.ZodObject<{
@@ -183,7 +183,7 @@ export declare const InviteCreateOutput: z.ZodObject<{
183
183
  }, z.core.$strict>;
184
184
  export type InviteCreateOutput = z.infer<typeof InviteCreateOutput>;
185
185
  /** Input for `invite_list`. */
186
- export declare const InviteListInput: z.ZodNull;
186
+ export declare const InviteListInput: z.ZodVoid;
187
187
  export type InviteListInput = z.infer<typeof InviteListInput>;
188
188
  /** Output for `invite_list`. Uses the enriched row including creator/claimer usernames. */
189
189
  export declare const InviteListOutput: z.ZodObject<{
@@ -211,7 +211,7 @@ export declare const InviteDeleteOutput: z.ZodObject<{
211
211
  }, z.core.$strict>;
212
212
  export type InviteDeleteOutput = z.infer<typeof InviteDeleteOutput>;
213
213
  /** Input for `app_settings_get`. No parameters. */
214
- export declare const AppSettingsGetInput: z.ZodNull;
214
+ export declare const AppSettingsGetInput: z.ZodVoid;
215
215
  export type AppSettingsGetInput = z.infer<typeof AppSettingsGetInput>;
216
216
  /** Output for `app_settings_get`. */
217
217
  export declare const AppSettingsGetOutput: z.ZodObject<{
@@ -247,7 +247,7 @@ export declare const admin_account_list_action_spec: {
247
247
  role: string;
248
248
  };
249
249
  side_effects: false;
250
- input: z.ZodNull;
250
+ input: z.ZodVoid;
251
251
  output: z.ZodObject<{
252
252
  accounts: z.ZodArray<z.ZodObject<{
253
253
  account: z.ZodObject<{
@@ -294,7 +294,7 @@ export declare const admin_session_list_action_spec: {
294
294
  role: string;
295
295
  };
296
296
  side_effects: false;
297
- input: z.ZodNull;
297
+ input: z.ZodVoid;
298
298
  output: z.ZodObject<{
299
299
  sessions: z.ZodArray<z.ZodObject<{
300
300
  id: z.ZodString;
@@ -454,7 +454,7 @@ export declare const invite_list_action_spec: {
454
454
  role: string;
455
455
  };
456
456
  side_effects: false;
457
- input: z.ZodNull;
457
+ input: z.ZodVoid;
458
458
  output: z.ZodObject<{
459
459
  invites: z.ZodArray<z.ZodObject<{
460
460
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
@@ -496,7 +496,7 @@ export declare const app_settings_get_action_spec: {
496
496
  role: string;
497
497
  };
498
498
  side_effects: false;
499
- input: z.ZodNull;
499
+ input: z.ZodVoid;
500
500
  output: z.ZodObject<{
501
501
  settings: z.ZodObject<{
502
502
  open_signup: z.ZodBoolean;
@@ -26,14 +26,14 @@ import { AppSettingsWithUsernameJson } from './app_settings_schema.js';
26
26
  export const AUDIT_LOG_LIST_LIMIT_MAX = 200;
27
27
  // -- Input/output schemas ---------------------------------------------------
28
28
  /** Input for `admin_account_list`. No parameters — the caller is the subject. */
29
- export const AdminAccountListInput = z.null();
29
+ export const AdminAccountListInput = z.void();
30
30
  /** Output for `admin_account_list`. */
31
31
  export const AdminAccountListOutput = z.strictObject({
32
32
  accounts: z.array(AdminAccountEntryJson),
33
33
  grantable_roles: z.array(RoleName),
34
34
  });
35
35
  /** Input for `admin_session_list`. No parameters — reads every active session. */
36
- export const AdminSessionListInput = z.null();
36
+ export const AdminSessionListInput = z.void();
37
37
  /** Output for `admin_session_list`. Cross-account listing; fan-out already scoped by role auth. */
38
38
  export const AdminSessionListOutput = z.strictObject({
39
39
  sessions: z.array(AdminSessionJson),
@@ -116,7 +116,7 @@ export const InviteCreateOutput = z.strictObject({
116
116
  invite: InviteJson,
117
117
  });
118
118
  /** Input for `invite_list`. */
119
- export const InviteListInput = z.null();
119
+ export const InviteListInput = z.void();
120
120
  /** Output for `invite_list`. Uses the enriched row including creator/claimer usernames. */
121
121
  export const InviteListOutput = z.strictObject({
122
122
  invites: z.array(InviteWithUsernamesJson),
@@ -130,7 +130,7 @@ export const InviteDeleteOutput = z.strictObject({
130
130
  ok: z.literal(true),
131
131
  });
132
132
  /** Input for `app_settings_get`. No parameters. */
133
- export const AppSettingsGetInput = z.null();
133
+ export const AppSettingsGetInput = z.void();
134
134
  /** Output for `app_settings_get`. */
135
135
  export const AppSettingsGetOutput = z.strictObject({
136
136
  settings: AppSettingsWithUsernameJson,
@@ -1,17 +1,20 @@
1
1
  /**
2
2
  * Auth schema migrations.
3
3
  *
4
- * Single v0 migration for the fuz identity system tables.
4
+ * Ordered list of `{name, up}` migrations for the fuz identity system tables.
5
5
  * Consumed by `run_migrations` with namespace `'fuz_auth'`.
6
6
  *
7
- * Collapsed to a single v0 for the 0.1.0 release — no production databases
8
- * exist, so the prior v0–v6 development iterations are consolidated.
9
- * Post-0.1.0, each new migration appends as v1, v2, etc.
7
+ * **Append-only after first publish.** Once a fuz_app version containing a
8
+ * given migration is published (`npm publish` / `jsr publish`), that
9
+ * migration's name and position are frozen. Never edit, rename, or reorder —
10
+ * append only. Pre-publish, anything goes; the cliff is the publish event.
11
+ * Body edits to a published migration slip past the runner (no content
12
+ * hashing) and are caught by schema-snapshot tests in consumers.
10
13
  *
11
14
  * To add a migration, append a new entry to `AUTH_MIGRATIONS`:
12
15
  *
13
16
  * ```ts
14
- * // v1: add display_name to account
17
+ * // v2: add display_name to account
15
18
  * {
16
19
  * name: 'account_display_name',
17
20
  * up: async (db) => {
@@ -21,8 +24,7 @@
21
24
  * ```
22
25
  *
23
26
  * Migrations are forward-only (no down). Use `IF NOT EXISTS` / `IF EXISTS`
24
- * for DDL safety. Named migrations (`{name, up}`) are preferred for
25
- * debuggability — the name appears in error messages on failure.
27
+ * for DDL safety. The `name` appears in error messages on failure.
26
28
  *
27
29
  * @module
28
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA6BH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AAEpE,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CA6D5C,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AA6BH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AAEpE,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CA6D5C,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
@@ -1,17 +1,20 @@
1
1
  /**
2
2
  * Auth schema migrations.
3
3
  *
4
- * Single v0 migration for the fuz identity system tables.
4
+ * Ordered list of `{name, up}` migrations for the fuz identity system tables.
5
5
  * Consumed by `run_migrations` with namespace `'fuz_auth'`.
6
6
  *
7
- * Collapsed to a single v0 for the 0.1.0 release — no production databases
8
- * exist, so the prior v0–v6 development iterations are consolidated.
9
- * Post-0.1.0, each new migration appends as v1, v2, etc.
7
+ * **Append-only after first publish.** Once a fuz_app version containing a
8
+ * given migration is published (`npm publish` / `jsr publish`), that
9
+ * migration's name and position are frozen. Never edit, rename, or reorder —
10
+ * append only. Pre-publish, anything goes; the cliff is the publish event.
11
+ * Body edits to a published migration slip past the runner (no content
12
+ * hashing) and are caught by schema-snapshot tests in consumers.
10
13
  *
11
14
  * To add a migration, append a new entry to `AUTH_MIGRATIONS`:
12
15
  *
13
16
  * ```ts
14
- * // v1: add display_name to account
17
+ * // v2: add display_name to account
15
18
  * {
16
19
  * name: 'account_display_name',
17
20
  * up: async (db) => {
@@ -21,8 +24,7 @@
21
24
  * ```
22
25
  *
23
26
  * Migrations are forward-only (no down). Use `IF NOT EXISTS` / `IF EXISTS`
24
- * for DDL safety. Named migrations (`{name, up}`) are preferred for
25
- * debuggability — the name appears in error messages on failure.
27
+ * for DDL safety. The `name` appears in error messages on failure.
26
28
  *
27
29
  * @module
28
30
  */