@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.
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +14 -7
- package/dist/auth/CLAUDE.md +96 -9
- package/dist/auth/account_action_specs.d.ts +8 -8
- package/dist/auth/account_action_specs.js +4 -4
- package/dist/auth/admin_action_specs.d.ts +8 -8
- package/dist/auth/admin_action_specs.js +4 -4
- package/dist/auth/migrations.d.ts +9 -7
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +9 -7
- package/dist/db/migrate.d.ts +124 -39
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +244 -75
- package/dist/db/status.d.ts +13 -7
- package/dist/db/status.d.ts.map +1 -1
- package/dist/db/status.js +56 -20
- package/dist/http/schema_helpers.d.ts +9 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +9 -0
- package/dist/server/app_backend.d.ts +3 -2
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/testing/CLAUDE.md +13 -13
- package/dist/testing/admin_integration.js +9 -9
- package/dist/testing/audit_completeness.js +3 -3
- package/dist/testing/db.d.ts +1 -1
- package/dist/testing/db.js +2 -2
- package/dist/testing/integration.js +36 -36
- package/dist/testing/rpc_helpers.d.ts +14 -6
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +8 -5
- package/dist/ui/admin_rpc_adapters.js +4 -4
- package/package.json +1 -1
package/dist/db/status.js
CHANGED
|
@@ -6,13 +6,29 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
+
const has_table_column = async (db, table_name, column_name) => {
|
|
10
|
+
const row = await db.query_one(`SELECT EXISTS (
|
|
11
|
+
SELECT 1 FROM information_schema.columns
|
|
12
|
+
WHERE table_schema = 'public'
|
|
13
|
+
AND table_name = $1
|
|
14
|
+
AND column_name = $2
|
|
15
|
+
) as exists`, [table_name, column_name]);
|
|
16
|
+
return row?.exists ?? false;
|
|
17
|
+
};
|
|
18
|
+
const has_table = async (db, table_name) => {
|
|
19
|
+
const row = await db.query_one(`SELECT EXISTS (
|
|
20
|
+
SELECT 1 FROM information_schema.tables
|
|
21
|
+
WHERE table_schema = 'public' AND table_name = $1
|
|
22
|
+
) as exists`, [table_name]);
|
|
23
|
+
return row?.exists ?? false;
|
|
24
|
+
};
|
|
9
25
|
/**
|
|
10
|
-
* Query database status including connectivity, tables, and migration
|
|
26
|
+
* Query database status including connectivity, tables, and migration state.
|
|
11
27
|
*
|
|
12
28
|
* Designed for CLI `db:status` commands. Does not modify the database.
|
|
13
29
|
*
|
|
14
30
|
* @param db - the database instance
|
|
15
|
-
* @param namespaces - migration namespaces to check
|
|
31
|
+
* @param namespaces - migration namespaces to check status for
|
|
16
32
|
* @returns a snapshot of database status
|
|
17
33
|
*/
|
|
18
34
|
export const query_db_status = async (db, namespaces) => {
|
|
@@ -42,34 +58,42 @@ export const query_db_status = async (db, namespaces) => {
|
|
|
42
58
|
row_count: result ? parseInt(result.count, 10) : 0,
|
|
43
59
|
});
|
|
44
60
|
}
|
|
45
|
-
// check migration
|
|
61
|
+
// check migration state
|
|
46
62
|
const migrations = [];
|
|
63
|
+
let old_tracker_shape;
|
|
47
64
|
if (namespaces?.length) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (sv_exists
|
|
65
|
+
const sv_exists = await has_table(db, 'schema_version');
|
|
66
|
+
// pre-0.42 shape carries a `version` column; new shape carries `name`
|
|
67
|
+
const old_shape = sv_exists ? await has_table_column(db, 'schema_version', 'version') : false;
|
|
68
|
+
if (old_shape)
|
|
69
|
+
old_tracker_shape = true;
|
|
70
|
+
if (sv_exists && !old_shape) {
|
|
54
71
|
for (const { namespace, migrations: ns_migrations } of namespaces) {
|
|
55
|
-
const
|
|
56
|
-
|
|
72
|
+
const rows = await db.query(`SELECT name FROM schema_version
|
|
73
|
+
WHERE namespace = $1
|
|
74
|
+
ORDER BY sequence ASC`, [namespace]);
|
|
75
|
+
const applied_names = rows.map((r) => r.name);
|
|
76
|
+
const code_names = ns_migrations.map((m) => m.name);
|
|
77
|
+
// pending = the suffix of code names beyond applied.length (callers
|
|
78
|
+
// see the boot algorithm's tail without paying for verify here)
|
|
79
|
+
const pending_names = code_names.slice(applied_names.length);
|
|
57
80
|
migrations.push({
|
|
58
81
|
namespace,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
up_to_date:
|
|
82
|
+
applied_names,
|
|
83
|
+
pending_names,
|
|
84
|
+
up_to_date: applied_names.length === code_names.length && pending_names.length === 0,
|
|
62
85
|
});
|
|
63
86
|
}
|
|
64
87
|
}
|
|
65
88
|
else {
|
|
66
|
-
// no
|
|
89
|
+
// no tracker, or pre-0.42 shape — every namespace shows as "nothing applied yet"
|
|
67
90
|
for (const { namespace, migrations: ns_migrations } of namespaces) {
|
|
91
|
+
const code_names = ns_migrations.map((m) => m.name);
|
|
68
92
|
migrations.push({
|
|
69
93
|
namespace,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
up_to_date:
|
|
94
|
+
applied_names: [],
|
|
95
|
+
pending_names: code_names,
|
|
96
|
+
up_to_date: code_names.length === 0,
|
|
73
97
|
});
|
|
74
98
|
}
|
|
75
99
|
}
|
|
@@ -79,6 +103,7 @@ export const query_db_status = async (db, namespaces) => {
|
|
|
79
103
|
table_count: tables.length,
|
|
80
104
|
tables,
|
|
81
105
|
migrations,
|
|
106
|
+
...(old_tracker_shape ? { old_tracker_shape: true } : {}),
|
|
82
107
|
};
|
|
83
108
|
};
|
|
84
109
|
/**
|
|
@@ -102,12 +127,23 @@ export const format_db_status = (status) => {
|
|
|
102
127
|
lines.push(` ${t.name.padEnd(max_name)} ${t.row_count} rows`);
|
|
103
128
|
}
|
|
104
129
|
}
|
|
130
|
+
if (status.old_tracker_shape) {
|
|
131
|
+
lines.push('');
|
|
132
|
+
lines.push(' Migrations: pre-0.42 schema_version shape detected.');
|
|
133
|
+
lines.push(' Drop the table and re-run, or call `baseline()` first if preserving the schema.');
|
|
134
|
+
}
|
|
105
135
|
if (status.migrations.length > 0) {
|
|
106
136
|
lines.push('');
|
|
107
137
|
lines.push(' Migrations:');
|
|
108
138
|
for (const m of status.migrations) {
|
|
109
|
-
const
|
|
110
|
-
|
|
139
|
+
const total = m.applied_names.length + m.pending_names.length;
|
|
140
|
+
if (m.up_to_date) {
|
|
141
|
+
lines.push(` ${m.namespace}: up to date (${m.applied_names.length}/${total})`);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const pending_list = m.pending_names.join(', ');
|
|
145
|
+
lines.push(` ${m.namespace}: applied ${m.applied_names.length}/${total} (pending: ${pending_list})`);
|
|
146
|
+
}
|
|
111
147
|
}
|
|
112
148
|
}
|
|
113
149
|
return lines.join('\n');
|
|
@@ -18,6 +18,15 @@ import { type RateLimitKey, type RouteErrorSchemas } from './error_schemas.js';
|
|
|
18
18
|
* but also accept other values.
|
|
19
19
|
*/
|
|
20
20
|
export declare const is_null_schema: (schema: z.ZodType) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a schema is exactly `z.void()`.
|
|
23
|
+
*
|
|
24
|
+
* RPC action specs use `z.void()` to declare a parameterless method —
|
|
25
|
+
* JSON-RPC 2.0 forbids `params: null` (params must be omitted or be a
|
|
26
|
+
* Structured value), so `z.void()` is the correct schema for "no params"
|
|
27
|
+
* and the dispatcher maps absent params to `undefined` for these specs.
|
|
28
|
+
*/
|
|
29
|
+
export declare const is_void_schema: (schema: z.ZodType) => boolean;
|
|
21
30
|
/**
|
|
22
31
|
* Check if a schema is a strict object (`z.strictObject()`).
|
|
23
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAUtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,KAC1C,iBAAiB,GAAG,IAUtB,CAAC"}
|
|
@@ -17,6 +17,15 @@ import { derive_error_schemas } from './error_schemas.js';
|
|
|
17
17
|
* but also accept other values.
|
|
18
18
|
*/
|
|
19
19
|
export const is_null_schema = (schema) => schema instanceof z.ZodNull;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a schema is exactly `z.void()`.
|
|
22
|
+
*
|
|
23
|
+
* RPC action specs use `z.void()` to declare a parameterless method —
|
|
24
|
+
* JSON-RPC 2.0 forbids `params: null` (params must be omitted or be a
|
|
25
|
+
* Structured value), so `z.void()` is the correct schema for "no params"
|
|
26
|
+
* and the dispatcher maps absent params to `undefined` for these specs.
|
|
27
|
+
*/
|
|
28
|
+
export const is_void_schema = (schema) => schema instanceof z.ZodVoid;
|
|
20
29
|
/**
|
|
21
30
|
* Check if a schema is a strict object (`z.strictObject()`).
|
|
22
31
|
*
|
|
@@ -70,8 +70,9 @@ export interface CreateAppBackendOptions {
|
|
|
70
70
|
audit_log_config?: AuditLogConfig;
|
|
71
71
|
/**
|
|
72
72
|
* Additional migration namespaces to run after the builtin auth namespace.
|
|
73
|
-
*
|
|
74
|
-
* append-only so forward-only
|
|
73
|
+
* The shared `schema_version` table records one row per applied migration
|
|
74
|
+
* (`namespace`, `name`, `sequence`); order is append-only so forward-only
|
|
75
|
+
* guarantees hold per-namespace.
|
|
75
76
|
*
|
|
76
77
|
* The reserved `'fuz_auth'` namespace is rejected at startup. Omit for no
|
|
77
78
|
* extra namespaces. This is the only place to splice consumer migrations
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_backend.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAE/C,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,cAAc,EAAE,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAiB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAI/F;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oIAAoI;IACpI,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC3D,iEAAiE;IACjE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,+DAA+D;IAC/D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,2BAA2B;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC
|
|
1
|
+
{"version":3,"file":"app_backend.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAE/C,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,cAAc,EAAE,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/E,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAiB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAI/F;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,oIAAoI;IACpI,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC3D,iEAAiE;IACjE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACvC,+DAA+D;IAC/D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,2BAA2B;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACzD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAU,SAAS,uBAAuB,KAAG,OAAO,CAAC,UAAU,CAoC7F,CAAC"}
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -81,19 +81,19 @@ Factory builders for parameterized DB tests. Consumer projects pass their
|
|
|
81
81
|
`init_schema` callback (which calls `run_migrations(db, [AUTH_MIGRATION_NS, ...app_migrations])`);
|
|
82
82
|
factories accept any migration namespace set.
|
|
83
83
|
|
|
84
|
-
| Helper | Role
|
|
85
|
-
| ------------------------------------------------ |
|
|
86
|
-
| `IS_CI` | `process.env.CI === 'true'` — CI detection.
|
|
87
|
-
| `DbFactory` interface | `{name, create, close, skip, skip_reason?}`.
|
|
88
|
-
| `reset_pglite(db)` | `DROP SCHEMA public CASCADE` + recreate. Reuses a live PGlite instance.
|
|
89
|
-
| `create_pglite_factory(init_schema)` | In-memory; no external deps; `skip: false`. See WASM caching below.
|
|
90
|
-
| `create_pg_factory(init_schema, test_url?)` | PostgreSQL; `skip: true` when `test_url` is missing; drops `schema_version` before `init_schema` so migrations re-evaluate against actual tables; pool is reused + cleaned up across `create()` calls.
|
|
91
|
-
| `AUTH_TRUNCATE_TABLES` | `['invite', 'api_token', 'auth_session', 'permit', 'permit_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it.
|
|
92
|
-
| `AUTH_INTEGRATION_TRUNCATE_TABLES` | `AUTH_TRUNCATE_TABLES + ['audit_log']` — for integration suites that exercise the audit path.
|
|
93
|
-
| `AUTH_DROP_TABLES` | Full set from `AUTH_MIGRATIONS` in drop order; call `drop_auth_schema(db)` at the top of `init_schema` on persistent pg databases that may hold stale DDL from previous fuz_app versions.
|
|
94
|
-
| `drop_auth_schema(db)` | `DROP TABLE IF EXISTS <table> CASCADE` for every entry in `AUTH_DROP_TABLES` plus `schema_version`. Safe on fresh DBs.
|
|
95
|
-
| `create_describe_db(factories, truncate_tables)` | Returns `describe_db(name, fn)` that runs `fn(get_db)` once per factory, inside a `describe` block with shared `beforeAll(create)` + `beforeEach(TRUNCATE)` + `afterAll(close)`. Skipped factories use `describe.skip`.
|
|
96
|
-
| `log_db_factory_status(factories)` | Console summary of enabled / skipped factories.
|
|
84
|
+
| Helper | Role |
|
|
85
|
+
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
86
|
+
| `IS_CI` | `process.env.CI === 'true'` — CI detection. |
|
|
87
|
+
| `DbFactory` interface | `{name, create, close, skip, skip_reason?}`. |
|
|
88
|
+
| `reset_pglite(db)` | `DROP SCHEMA public CASCADE` + recreate. Reuses a live PGlite instance. |
|
|
89
|
+
| `create_pglite_factory(init_schema)` | In-memory; no external deps; `skip: false`. See WASM caching below. |
|
|
90
|
+
| `create_pg_factory(init_schema, test_url?)` | PostgreSQL; `skip: true` when `test_url` is missing; drops `schema_version` before `init_schema` so migrations re-evaluate against actual tables (prevents stale tracker rows from skipping migrations when DDL changes between test sessions); pool is reused + cleaned up across `create()` calls. |
|
|
91
|
+
| `AUTH_TRUNCATE_TABLES` | `['invite', 'api_token', 'auth_session', 'permit', 'permit_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it. |
|
|
92
|
+
| `AUTH_INTEGRATION_TRUNCATE_TABLES` | `AUTH_TRUNCATE_TABLES + ['audit_log']` — for integration suites that exercise the audit path. |
|
|
93
|
+
| `AUTH_DROP_TABLES` | Full set from `AUTH_MIGRATIONS` in drop order; call `drop_auth_schema(db)` at the top of `init_schema` on persistent pg databases that may hold stale DDL from previous fuz_app versions. |
|
|
94
|
+
| `drop_auth_schema(db)` | `DROP TABLE IF EXISTS <table> CASCADE` for every entry in `AUTH_DROP_TABLES` plus `schema_version`. Safe on fresh DBs. |
|
|
95
|
+
| `create_describe_db(factories, truncate_tables)` | Returns `describe_db(name, fn)` that runs `fn(get_db)` once per factory, inside a `describe` block with shared `beforeAll(create)` + `beforeEach(TRUNCATE)` + `afterAll(close)`. Skipped factories use `describe.skip`. |
|
|
96
|
+
| `log_db_factory_status(factories)` | Console summary of enabled / skipped factories. |
|
|
97
97
|
|
|
98
98
|
**PGlite WASM caching.** `create_pglite_factory` shares a single PGlite
|
|
99
99
|
instance in a module-level ref (`module_db`) across all factories in the
|
|
@@ -163,7 +163,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
163
163
|
app: test_app.app,
|
|
164
164
|
path: rpc_path,
|
|
165
165
|
spec: admin_account_list_action_spec,
|
|
166
|
-
params:
|
|
166
|
+
params: undefined,
|
|
167
167
|
headers: test_app.create_session_headers(),
|
|
168
168
|
});
|
|
169
169
|
assert.ok(res.ok, `admin_account_list failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
@@ -181,7 +181,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
181
181
|
app: test_app.app,
|
|
182
182
|
path: rpc_path,
|
|
183
183
|
spec: admin_account_list_action_spec,
|
|
184
|
-
params:
|
|
184
|
+
params: undefined,
|
|
185
185
|
headers: test_app.create_session_headers(),
|
|
186
186
|
});
|
|
187
187
|
assert.ok(!res.ok, 'Expected admin_account_list to fail for non-admin');
|
|
@@ -205,7 +205,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
205
205
|
app: test_app.app,
|
|
206
206
|
path: rpc_path,
|
|
207
207
|
spec: admin_session_list_action_spec,
|
|
208
|
-
params:
|
|
208
|
+
params: undefined,
|
|
209
209
|
headers: test_app.create_session_headers(),
|
|
210
210
|
});
|
|
211
211
|
assert.ok(res.ok, `admin_session_list failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
@@ -220,7 +220,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
220
220
|
app: test_app.app,
|
|
221
221
|
path: rpc_path,
|
|
222
222
|
spec: account_verify_action_spec,
|
|
223
|
-
params:
|
|
223
|
+
params: undefined,
|
|
224
224
|
headers: create_headers(user_two.session_cookie),
|
|
225
225
|
});
|
|
226
226
|
assert.strictEqual(before.status, 200);
|
|
@@ -240,7 +240,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
240
240
|
app: test_app.app,
|
|
241
241
|
path: rpc_path,
|
|
242
242
|
spec: account_verify_action_spec,
|
|
243
|
-
params:
|
|
243
|
+
params: undefined,
|
|
244
244
|
headers: create_headers(user_two.session_cookie),
|
|
245
245
|
});
|
|
246
246
|
assert.strictEqual(after.status, 401);
|
|
@@ -263,7 +263,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
263
263
|
app: test_app.app,
|
|
264
264
|
path: rpc_path,
|
|
265
265
|
spec: account_verify_action_spec,
|
|
266
|
-
params:
|
|
266
|
+
params: undefined,
|
|
267
267
|
headers: test_app.create_session_headers(),
|
|
268
268
|
});
|
|
269
269
|
assert.strictEqual(after.status, 401);
|
|
@@ -279,7 +279,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
279
279
|
app: test_app.app,
|
|
280
280
|
path: rpc_path,
|
|
281
281
|
spec: account_verify_action_spec,
|
|
282
|
-
params:
|
|
282
|
+
params: undefined,
|
|
283
283
|
headers: { authorization: `Bearer ${user_two.api_token}` },
|
|
284
284
|
suppress_default_origin: true,
|
|
285
285
|
});
|
|
@@ -300,7 +300,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
300
300
|
app: test_app.app,
|
|
301
301
|
path: rpc_path,
|
|
302
302
|
spec: account_verify_action_spec,
|
|
303
|
-
params:
|
|
303
|
+
params: undefined,
|
|
304
304
|
headers: { authorization: `Bearer ${user_two.api_token}` },
|
|
305
305
|
suppress_default_origin: true,
|
|
306
306
|
});
|
|
@@ -725,7 +725,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
725
725
|
app: test_app.app,
|
|
726
726
|
path: rpc_path,
|
|
727
727
|
spec: admin_account_list_action_spec,
|
|
728
|
-
params:
|
|
728
|
+
params: undefined,
|
|
729
729
|
headers: create_headers(regular_user.session_cookie),
|
|
730
730
|
});
|
|
731
731
|
assert.ok(!res.ok, 'Expected admin_account_list to fail for non-admin');
|
|
@@ -144,7 +144,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
144
144
|
app: test_app.app,
|
|
145
145
|
path: rpc_path,
|
|
146
146
|
spec: account_token_list_action_spec,
|
|
147
|
-
params:
|
|
147
|
+
params: undefined,
|
|
148
148
|
headers: test_app.create_session_headers(),
|
|
149
149
|
});
|
|
150
150
|
assert.ok(list_res.ok, 'account_token_list should succeed');
|
|
@@ -179,7 +179,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
179
179
|
app: test_app.app,
|
|
180
180
|
path: rpc_path,
|
|
181
181
|
spec: account_session_list_action_spec,
|
|
182
|
-
params:
|
|
182
|
+
params: undefined,
|
|
183
183
|
headers: test_app.create_session_headers(),
|
|
184
184
|
});
|
|
185
185
|
assert.ok(list_res.ok, 'account_session_list should succeed');
|
|
@@ -203,7 +203,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
203
203
|
app: test_app.app,
|
|
204
204
|
path: rpc_path,
|
|
205
205
|
spec: account_session_revoke_all_action_spec,
|
|
206
|
-
params:
|
|
206
|
+
params: undefined,
|
|
207
207
|
headers: test_app.create_session_headers(),
|
|
208
208
|
});
|
|
209
209
|
assert.ok(res.ok, `account_session_revoke_all failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
package/dist/testing/db.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare const create_pglite_factory: (init_schema: (db: Db) => Promise<vo
|
|
|
41
41
|
*
|
|
42
42
|
* Skipped when `test_url` is not provided.
|
|
43
43
|
* Drops `schema_version` before running `init_schema`, forcing migrations
|
|
44
|
-
* to re-evaluate against the actual tables. Prevents stale
|
|
44
|
+
* to re-evaluate against the actual tables. Prevents stale tracker rows
|
|
45
45
|
* from skipping migrations when DDL changes between test sessions.
|
|
46
46
|
*
|
|
47
47
|
* For full clean-slate behavior (recommended), call `drop_auth_schema(db)`
|
package/dist/testing/db.js
CHANGED
|
@@ -82,7 +82,7 @@ export const create_pglite_factory = (init_schema) => ({
|
|
|
82
82
|
*
|
|
83
83
|
* Skipped when `test_url` is not provided.
|
|
84
84
|
* Drops `schema_version` before running `init_schema`, forcing migrations
|
|
85
|
-
* to re-evaluate against the actual tables. Prevents stale
|
|
85
|
+
* to re-evaluate against the actual tables. Prevents stale tracker rows
|
|
86
86
|
* from skipping migrations when DDL changes between test sessions.
|
|
87
87
|
*
|
|
88
88
|
* For full clean-slate behavior (recommended), call `drop_auth_schema(db)`
|
|
@@ -122,7 +122,7 @@ export const create_pg_factory = (init_schema, test_url) => {
|
|
|
122
122
|
const { db } = create_pg_db(pool);
|
|
123
123
|
try {
|
|
124
124
|
// Drop schema_version so migrations re-evaluate against the actual
|
|
125
|
-
// tables. Prevents stale
|
|
125
|
+
// tables. Prevents stale tracker rows from skipping migrations
|
|
126
126
|
// when DDL changes between test sessions. Migrations use
|
|
127
127
|
// IF NOT EXISTS guards, so re-running is safe.
|
|
128
128
|
await db.query('DROP TABLE IF EXISTS schema_version');
|