@percher/core 0.4.9 → 0.4.11
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/ai-files-manifest.d.ts +1 -1
- package/dist/commands/account.d.ts +1 -1
- package/dist/commands/account.js +2 -2
- package/dist/commands/admin-reconcile-routes.d.ts +1 -1
- package/dist/commands/ai-files.d.ts +2 -2
- package/dist/commands/ai-files.js +2 -2
- package/dist/commands/alerts.d.ts +1 -1
- package/dist/commands/app-resources.d.ts +1 -1
- package/dist/commands/app-resources.js +2 -2
- package/dist/commands/app-topology.d.ts +1 -1
- package/dist/commands/app-topology.js +2 -2
- package/dist/commands/billing.d.ts +1 -1
- package/dist/commands/billing.js +1 -1
- package/dist/commands/cache.d.ts +1 -1
- package/dist/commands/cache.js +2 -2
- package/dist/commands/capabilities.d.ts +1 -1
- package/dist/commands/claim.d.ts +1 -1
- package/dist/commands/claim.d.ts.map +1 -1
- package/dist/commands/claim.js +14 -9
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/create.d.ts +2 -2
- package/dist/commands/create.js +2 -2
- package/dist/commands/dashboard.d.ts +1 -1
- package/dist/commands/dashboard.js +2 -2
- package/dist/commands/data-export.d.ts +1 -1
- package/dist/commands/data-export.js +3 -3
- package/dist/commands/data.d.ts +1 -1
- package/dist/commands/data.js +2 -2
- package/dist/commands/delete.d.ts +1 -1
- package/dist/commands/delete.js +2 -2
- package/dist/commands/deploys.d.ts +1 -1
- package/dist/commands/deploys.js +2 -2
- package/dist/commands/dev.d.ts +1 -1
- package/dist/commands/dev.js +3 -3
- package/dist/commands/diagnose.d.ts +1 -1
- package/dist/commands/diagnose.js +2 -2
- package/dist/commands/diff.d.ts +1 -1
- package/dist/commands/diff.js +2 -2
- package/dist/commands/doctor.d.ts +3 -3
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/domains.d.ts +1 -1
- package/dist/commands/domains.js +2 -2
- package/dist/commands/env.d.ts +1 -1
- package/dist/commands/env.js +2 -2
- package/dist/commands/export.d.ts +1 -1
- package/dist/commands/export.js +2 -2
- package/dist/commands/forgejo.d.ts +1 -1
- package/dist/commands/forgejo.js +2 -2
- package/dist/commands/generate.d.ts +1 -1
- package/dist/commands/generate.js +1 -1
- package/dist/commands/github.d.ts +1 -1
- package/dist/commands/github.js +2 -2
- package/dist/commands/import-project.d.ts +1 -1
- package/dist/commands/import-project.js +2 -2
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.js +3 -3
- package/dist/commands/insights.d.ts +1 -1
- package/dist/commands/insights.js +2 -2
- package/dist/commands/inspect-link.d.ts +1 -1
- package/dist/commands/inspect-link.js +2 -2
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/logs.d.ts +1 -1
- package/dist/commands/logs.js +2 -2
- package/dist/commands/mcp.d.ts +1 -1
- package/dist/commands/migrate-supabase-map.d.ts +1 -1
- package/dist/commands/migrate-supabase-recipes.d.ts +28 -0
- package/dist/commands/migrate-supabase-recipes.d.ts.map +1 -0
- package/dist/commands/migrate-supabase-recipes.js +92 -0
- package/dist/commands/migrate-supabase-recipes.js.map +1 -0
- package/dist/commands/migrate-supabase-rewrite.d.ts +101 -0
- package/dist/commands/migrate-supabase-rewrite.d.ts.map +1 -0
- package/dist/commands/migrate-supabase-rewrite.js +459 -0
- package/dist/commands/migrate-supabase-rewrite.js.map +1 -0
- package/dist/commands/migrate-supabase-scaffold.d.ts +25 -0
- package/dist/commands/migrate-supabase-scaffold.d.ts.map +1 -0
- package/dist/commands/migrate-supabase-scaffold.js +234 -0
- package/dist/commands/migrate-supabase-scaffold.js.map +1 -0
- package/dist/commands/migrate-supabase-schema.d.ts +4 -4
- package/dist/commands/migrate-supabase-schema.js +4 -4
- package/dist/commands/migrate-supabase-scripts.d.ts +1 -1
- package/dist/commands/migrate-supabase-sdk.d.ts +34 -0
- package/dist/commands/migrate-supabase-sdk.d.ts.map +1 -1
- package/dist/commands/migrate-supabase-sdk.js +169 -0
- package/dist/commands/migrate-supabase-sdk.js.map +1 -1
- package/dist/commands/migrate-supabase-status.d.ts +92 -0
- package/dist/commands/migrate-supabase-status.d.ts.map +1 -0
- package/dist/commands/migrate-supabase-status.js +470 -0
- package/dist/commands/migrate-supabase-status.js.map +1 -0
- package/dist/commands/migrate-supabase-walker.d.ts +15 -1
- package/dist/commands/migrate-supabase-walker.d.ts.map +1 -1
- package/dist/commands/migrate-supabase-walker.js +49 -5
- package/dist/commands/migrate-supabase-walker.js.map +1 -1
- package/dist/commands/migrate-supabase.d.ts +2 -2
- package/dist/commands/migrate-supabase.js +1 -1
- package/dist/commands/open.d.ts +1 -1
- package/dist/commands/open.js +2 -2
- package/dist/commands/preview-branch.d.ts +1 -1
- package/dist/commands/preview-branch.js +2 -2
- package/dist/commands/publish-api-error.d.ts +1 -1
- package/dist/commands/publish-api-error.js +1 -1
- package/dist/commands/publish-failure.d.ts +3 -3
- package/dist/commands/publish-failure.js +3 -3
- package/dist/commands/publish.d.ts +3 -3
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +19 -21
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/push.d.ts +2 -2
- package/dist/commands/push.js +8 -8
- package/dist/commands/redeploy.d.ts +2 -2
- package/dist/commands/redeploy.js +4 -4
- package/dist/commands/rename.d.ts +1 -1
- package/dist/commands/rename.js +2 -2
- package/dist/commands/reproduce.d.ts +1 -1
- package/dist/commands/reproduce.js +1 -1
- package/dist/commands/reset-superuser.d.ts +1 -1
- package/dist/commands/reset-superuser.js +2 -2
- package/dist/commands/restore.d.ts +1 -1
- package/dist/commands/restore.js +2 -2
- package/dist/commands/resume.d.ts +1 -1
- package/dist/commands/resume.js +2 -2
- package/dist/commands/rollback.d.ts +1 -1
- package/dist/commands/rollback.js +2 -2
- package/dist/commands/sharing.d.ts +1 -1
- package/dist/commands/sharing.js +2 -2
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/transfers.d.ts +1 -1
- package/dist/commands/transfers.js +2 -2
- package/dist/commands/unsuspend.d.ts +1 -1
- package/dist/commands/versions.d.ts +1 -1
- package/dist/commands/versions.js +2 -2
- package/dist/commands/wait-deploy.d.ts +3 -3
- package/dist/commands/wait-deploy.js +3 -3
- package/dist/commands/whoami.d.ts +1 -1
- package/dist/detect.js +1 -1
- package/dist/index.d.ts +77 -74
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +76 -73
- package/dist/index.js.map +1 -1
- package/dist/poll-deployment.d.ts +1 -1
- package/dist/recovery.d.ts +1 -1
- package/dist/structured-error-codes.d.ts +1 -1
- package/dist/templates/ai-files/index.js +2 -2
- package/package.json +6 -3
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join, relative, resolve } from "node:path";
|
|
3
|
+
import crossSpawn from "cross-spawn";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { recoveryAsk, recoveryNone } from "../recovery.js";
|
|
6
|
+
import { scanSupabaseUsage } from "./migrate-supabase-sdk.js";
|
|
7
|
+
import { walkSupabaseProject } from "./migrate-supabase-walker.js";
|
|
8
|
+
/**
|
|
9
|
+
* Phase B — migration status doctor.
|
|
10
|
+
*
|
|
11
|
+
* Turns "what's left in a Supabase→PocketBase migration" from prose buried in
|
|
12
|
+
* REWRITE_NOTES.md into a runnable scoreboard. Read-only: it scans the project
|
|
13
|
+
* AS IT SITS (so it reflects manual edits + a prior `--apply`), never the
|
|
14
|
+
* Supabase project, never a token. It mirrors the rewriter's hybrid model —
|
|
15
|
+
* a migration legitimately stops in a HYBRID state (some calls PocketBase,
|
|
16
|
+
* some still Supabase because storage/rpc/realtime have no clean equivalent),
|
|
17
|
+
* and in that state keeping both SDKs + both env sets is CORRECT, not a miss.
|
|
18
|
+
*/
|
|
19
|
+
export const migrationStatusInputSchema = z.object({
|
|
20
|
+
rootDir: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Project root to scan. Relative paths resolve against ctx.cwd. Defaults to ctx.cwd."),
|
|
24
|
+
build: z
|
|
25
|
+
.boolean()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Also run the project's build as a final gate. Off by default — a half-migrated project legitimately fails to build, so the noise is opt-in."),
|
|
28
|
+
pbIdentifier: z
|
|
29
|
+
.string()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("PocketBase client identifier the rewrite used (defaults to `pb`). Pass the same value here that `rewrite_client` used, or the undefined-reference check can't see a custom identifier (e.g. `db`)."),
|
|
32
|
+
supabaseIdentifiers: z
|
|
33
|
+
.array(z.string())
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Supabase client variable names to recognise (beyond `supabase`)."),
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Pure analysis over a set of files. Used by the standalone doctor (on-disk
|
|
39
|
+
* source) AND by the rewrite report embed (the rewriter's output), so the
|
|
40
|
+
* artifact and the live command can't disagree.
|
|
41
|
+
*/
|
|
42
|
+
export function analyzeMigration(files, opts = {}) {
|
|
43
|
+
const pbName = opts.pbIdentifier ?? "pb";
|
|
44
|
+
const supabaseImportFiles = [];
|
|
45
|
+
const danglingPbFiles = [];
|
|
46
|
+
let authCalls = 0;
|
|
47
|
+
let storage = 0;
|
|
48
|
+
let rpc = 0;
|
|
49
|
+
let realtime = 0;
|
|
50
|
+
let edgeFunctions = 0;
|
|
51
|
+
let anyPbUsage = false;
|
|
52
|
+
let pocketbaseDepDeclared = false;
|
|
53
|
+
let supabaseDepDeclared = false;
|
|
54
|
+
let pocketbaseUrlEnv = false;
|
|
55
|
+
let supabaseEnvPresent = false;
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
if (file.kind === "code") {
|
|
58
|
+
const scan = scanSupabaseUsage({
|
|
59
|
+
source: file.source,
|
|
60
|
+
supabaseIdentifiers: opts.supabaseIdentifiers,
|
|
61
|
+
pbIdentifier: pbName,
|
|
62
|
+
});
|
|
63
|
+
if (scan.importsSupabase)
|
|
64
|
+
supabaseImportFiles.push(file.relativePath);
|
|
65
|
+
if (scan.danglingPb)
|
|
66
|
+
danglingPbFiles.push(file.relativePath);
|
|
67
|
+
if (scan.usesPb)
|
|
68
|
+
anyPbUsage = true;
|
|
69
|
+
authCalls += scan.authCalls;
|
|
70
|
+
storage += scan.storage;
|
|
71
|
+
rpc += scan.rpc;
|
|
72
|
+
realtime += scan.realtime;
|
|
73
|
+
edgeFunctions += scan.edgeFunctions;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (file.kind === "package_json") {
|
|
77
|
+
const deps = readDeps(file.source);
|
|
78
|
+
if ("pocketbase" in deps)
|
|
79
|
+
pocketbaseDepDeclared = true;
|
|
80
|
+
if ("@supabase/supabase-js" in deps || "@supabase/ssr" in deps)
|
|
81
|
+
supabaseDepDeclared = true;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// env
|
|
85
|
+
if (/^\s*[A-Z][A-Z0-9_]*POCKETBASE_URL\s*=/m.test(file.source))
|
|
86
|
+
pocketbaseUrlEnv = true;
|
|
87
|
+
if (/^\s*[A-Z][A-Z0-9_]*SUPABASE[A-Z0-9_]*\s*=/m.test(file.source))
|
|
88
|
+
supabaseEnvPresent = true;
|
|
89
|
+
}
|
|
90
|
+
const remaining = supabaseImportFiles.length + authCalls + storage + rpc + realtime + edgeFunctions;
|
|
91
|
+
const migrationComplete = remaining === 0;
|
|
92
|
+
const checks = [];
|
|
93
|
+
checks.push({
|
|
94
|
+
id: "supabaseImportsRemaining",
|
|
95
|
+
label: "Supabase imports removed",
|
|
96
|
+
status: supabaseImportFiles.length === 0 ? "pass" : "warn",
|
|
97
|
+
count: supabaseImportFiles.length,
|
|
98
|
+
detail: supabaseImportFiles.length === 0
|
|
99
|
+
? "No files import @supabase/*."
|
|
100
|
+
: `${supabaseImportFiles.length} file(s) still import @supabase/* — migrate them, or keep them if this is intentionally hybrid.`,
|
|
101
|
+
...(supabaseImportFiles.length > 0 ? { files: supabaseImportFiles } : {}),
|
|
102
|
+
});
|
|
103
|
+
checks.push({
|
|
104
|
+
id: "undefinedPbReferences",
|
|
105
|
+
label: "PocketBase client wired",
|
|
106
|
+
status: danglingPbFiles.length === 0 ? "pass" : "fail",
|
|
107
|
+
count: danglingPbFiles.length,
|
|
108
|
+
detail: danglingPbFiles.length === 0
|
|
109
|
+
? `Every \`${pbName}\` reference resolves to an imported client.`
|
|
110
|
+
: `${danglingPbFiles.length} file(s) use \`${pbName}\` with no import in scope — the app won't run. Scaffold + import a client: percher migrate-from-supabase --rewrite-client --scaffold-client.`,
|
|
111
|
+
...(danglingPbFiles.length > 0 ? { files: danglingPbFiles } : {}),
|
|
112
|
+
});
|
|
113
|
+
checks.push(usageCheck("authCallsRemaining", "Auth calls migrated", authCalls, "supabase.auth.* call(s) still to map — see the auth recipes in REWRITE_NOTES.md."));
|
|
114
|
+
checks.push(usageCheck("storageUsage", "Storage migrated", storage, "supabase.storage.* call(s) remain — PocketBase models files as record fields; rewrite by hand."));
|
|
115
|
+
checks.push(usageCheck("rpcUsage", "RPC migrated", rpc, "supabase.rpc(...) call(s) remain — move the logic into app code or a PB hook."));
|
|
116
|
+
checks.push(usageCheck("realtimeUsage", "Realtime migrated", realtime, "supabase.channel(...) call(s) remain — PB realtime uses pb.collection(c).subscribe(); the event shape differs."));
|
|
117
|
+
checks.push(usageCheck("edgeFunctionUsage", "Edge functions migrated", edgeFunctions, "supabase.functions.invoke(...) call(s) remain — host the function elsewhere and fetch it."));
|
|
118
|
+
// PocketBase dependency.
|
|
119
|
+
checks.push({
|
|
120
|
+
id: "pocketbaseDepDeclared",
|
|
121
|
+
label: "pocketbase dependency declared",
|
|
122
|
+
status: pocketbaseDepDeclared ? "pass" : anyPbUsage ? "warn" : "n/a",
|
|
123
|
+
count: 0,
|
|
124
|
+
detail: pocketbaseDepDeclared
|
|
125
|
+
? "package.json depends on pocketbase."
|
|
126
|
+
: anyPbUsage
|
|
127
|
+
? "Your code uses `pb` but package.json has no `pocketbase` dependency — add it."
|
|
128
|
+
: "No PocketBase client in use yet.",
|
|
129
|
+
});
|
|
130
|
+
// Supabase cleanup (hybrid-aware): keeping the dep while usage remains is
|
|
131
|
+
// correct; dropping it while usage remains is broken.
|
|
132
|
+
checks.push(cleanupCheck({ migrationComplete, supabaseDepDeclared, remaining, anyPbUsage }));
|
|
133
|
+
// Env wiring — POCKETBASE_URL is injected by Percher in prod, so its absence
|
|
134
|
+
// in a local env file is a gentle warn, not a failure. Only relevant when
|
|
135
|
+
// PocketBase is ACTUALLY in use: a project with no pb usage (incl. a
|
|
136
|
+
// non-Supabase project that's vacuously "complete") needs no POCKETBASE_URL,
|
|
137
|
+
// so this is n/a — warning there is a false alarm.
|
|
138
|
+
checks.push({
|
|
139
|
+
id: "envWired",
|
|
140
|
+
label: "POCKETBASE_URL in env",
|
|
141
|
+
status: pocketbaseUrlEnv ? "pass" : anyPbUsage ? "warn" : "n/a",
|
|
142
|
+
count: 0,
|
|
143
|
+
detail: pocketbaseUrlEnv
|
|
144
|
+
? "POCKETBASE_URL is set for local dev."
|
|
145
|
+
: anyPbUsage
|
|
146
|
+
? "No POCKETBASE_URL in your env files. Percher injects it automatically in production; add it to .env for local dev."
|
|
147
|
+
: "No PocketBase env needed yet.",
|
|
148
|
+
});
|
|
149
|
+
// RLS rules to translate — parsed from MIGRATION_NOTES.md when present.
|
|
150
|
+
const rls = opts.rlsManualCount ?? null;
|
|
151
|
+
checks.push({
|
|
152
|
+
id: "rlsRulesToWrite",
|
|
153
|
+
label: "RLS → PB API rules",
|
|
154
|
+
status: rls === null ? "n/a" : rls === 0 ? "pass" : "warn",
|
|
155
|
+
count: rls ?? 0,
|
|
156
|
+
detail: rls === null
|
|
157
|
+
? "No migration-preview/MIGRATION_NOTES.md — run migrate-from-supabase to generate the schema + RLS report."
|
|
158
|
+
: rls === 0
|
|
159
|
+
? "No RLS policies need manual translation."
|
|
160
|
+
: `${rls} RLS policy/policies still need PB API rules — see migration-preview/MIGRATION_NOTES.md.`,
|
|
161
|
+
});
|
|
162
|
+
let supabaseEnvNote = "";
|
|
163
|
+
if (!migrationComplete && !supabaseEnvPresent && supabaseDepDeclared) {
|
|
164
|
+
// The dep is present but the SUPABASE_* env was dropped while usage
|
|
165
|
+
// remains — flag it on the env check's detail (don't fail outright; the
|
|
166
|
+
// env may be platform-injected).
|
|
167
|
+
supabaseEnvNote =
|
|
168
|
+
" Note: Supabase calls remain but no SUPABASE_* env was found — make sure those keys are still set.";
|
|
169
|
+
}
|
|
170
|
+
if (supabaseEnvNote) {
|
|
171
|
+
const envCheck = checks.find((c) => c.id === "envWired");
|
|
172
|
+
if (envCheck)
|
|
173
|
+
envCheck.detail += supabaseEnvNote;
|
|
174
|
+
}
|
|
175
|
+
const state = deriveState(checks, migrationComplete, anyPbUsage, remaining);
|
|
176
|
+
return { checks, migrationComplete, state };
|
|
177
|
+
}
|
|
178
|
+
function usageCheck(id, label, count, remainingDetail) {
|
|
179
|
+
return {
|
|
180
|
+
id,
|
|
181
|
+
label,
|
|
182
|
+
status: count === 0 ? "pass" : "warn",
|
|
183
|
+
count,
|
|
184
|
+
detail: count === 0 ? "None remaining." : `${count} ${remainingDetail}`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function cleanupCheck(args) {
|
|
188
|
+
const base = { id: "supabaseCleanup", label: "Supabase removed", count: args.remaining };
|
|
189
|
+
if (args.migrationComplete) {
|
|
190
|
+
if (args.supabaseDepDeclared) {
|
|
191
|
+
return {
|
|
192
|
+
...base,
|
|
193
|
+
status: "warn",
|
|
194
|
+
detail: "Migration looks complete — you can now drop @supabase/supabase-js and the Supabase env keys.",
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return { ...base, status: "pass", detail: "Supabase fully removed." };
|
|
198
|
+
}
|
|
199
|
+
// Migration NOT complete.
|
|
200
|
+
if (!args.supabaseDepDeclared && args.remaining > 0) {
|
|
201
|
+
return {
|
|
202
|
+
...base,
|
|
203
|
+
status: "fail",
|
|
204
|
+
detail: `@supabase/supabase-js was dropped but ${args.remaining} Supabase reference(s) still need it — restore the dependency or finish migrating them.`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
...base,
|
|
209
|
+
status: "warn",
|
|
210
|
+
detail: `Hybrid: ${args.remaining} Supabase reference(s) remain (storage/rpc/realtime/edge/un-mapped auth or @supabase imports). Keep @supabase/supabase-js + Supabase env until they're migrated.`,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function deriveState(checks, migrationComplete, anyPbUsage, remaining) {
|
|
214
|
+
if (checks.some((c) => c.status === "fail"))
|
|
215
|
+
return "broken";
|
|
216
|
+
if (migrationComplete)
|
|
217
|
+
return "complete";
|
|
218
|
+
if (anyPbUsage)
|
|
219
|
+
return "hybrid";
|
|
220
|
+
// Supabase usage present, nothing migrated to pb yet.
|
|
221
|
+
return remaining > 0 ? "not_started" : "complete";
|
|
222
|
+
}
|
|
223
|
+
/** Parse a package.json's dependency names across all dep sections. */
|
|
224
|
+
function readDeps(source) {
|
|
225
|
+
let pkg;
|
|
226
|
+
try {
|
|
227
|
+
pkg = JSON.parse(source);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return {};
|
|
231
|
+
}
|
|
232
|
+
const out = {};
|
|
233
|
+
for (const section of [
|
|
234
|
+
"dependencies",
|
|
235
|
+
"devDependencies",
|
|
236
|
+
"peerDependencies",
|
|
237
|
+
"optionalDependencies",
|
|
238
|
+
]) {
|
|
239
|
+
const deps = pkg[section];
|
|
240
|
+
if (deps && typeof deps === "object" && !Array.isArray(deps)) {
|
|
241
|
+
Object.assign(out, deps);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
const STATUS_GLYPH = {
|
|
247
|
+
pass: "✓",
|
|
248
|
+
fail: "✗",
|
|
249
|
+
warn: "⚠",
|
|
250
|
+
"n/a": "•",
|
|
251
|
+
};
|
|
252
|
+
/** Render the checklist as a plain ✓/✗/⚠ block (CLI output + report embed). */
|
|
253
|
+
export function renderMigrationChecklist(checks) {
|
|
254
|
+
const lines = [];
|
|
255
|
+
for (const check of checks) {
|
|
256
|
+
const glyph = STATUS_GLYPH[check.status];
|
|
257
|
+
const countSuffix = check.count > 0 ? ` (${check.count})` : "";
|
|
258
|
+
lines.push(`${glyph} ${check.label}${countSuffix} — ${check.detail}`);
|
|
259
|
+
if (check.files && check.files.length > 0) {
|
|
260
|
+
for (const f of check.files.slice(0, 10))
|
|
261
|
+
lines.push(` - ${f}`);
|
|
262
|
+
if (check.files.length > 10)
|
|
263
|
+
lines.push(` …and ${check.files.length - 10} more`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return lines.join("\n");
|
|
267
|
+
}
|
|
268
|
+
const STATE_SUMMARY = {
|
|
269
|
+
broken: "Migration is in a broken state — fix the ✗ items before deploying.",
|
|
270
|
+
hybrid: "Hybrid migration — some calls are on PocketBase, some still on Supabase (both SDKs needed).",
|
|
271
|
+
not_started: "Supabase is still in use — nothing migrated to PocketBase yet.",
|
|
272
|
+
complete: "Migration looks complete — no Supabase usage remains.",
|
|
273
|
+
};
|
|
274
|
+
export async function migrationStatus(ctx, input) {
|
|
275
|
+
const rootAbs = input.rootDir ? resolve(ctx.cwd, input.rootDir) : resolve(ctx.cwd);
|
|
276
|
+
ctx.status(`Scanning ${relative(ctx.cwd, rootAbs) || "."} for migration status...`);
|
|
277
|
+
let files;
|
|
278
|
+
try {
|
|
279
|
+
const walk = await walkSupabaseProject({ rootDir: rootAbs });
|
|
280
|
+
// Scan the CURRENT on-disk source (file.source), not the rewriter's
|
|
281
|
+
// projection — the doctor reports the project as it actually sits.
|
|
282
|
+
files = walk.files.map((f) => ({
|
|
283
|
+
relativePath: f.relativePath,
|
|
284
|
+
kind: f.kind,
|
|
285
|
+
source: f.source,
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
return failure(rootAbs, err);
|
|
290
|
+
}
|
|
291
|
+
const rlsManualCount = await readManualRlsCount(rootAbs);
|
|
292
|
+
const analysis = analyzeMigration(files, {
|
|
293
|
+
rlsManualCount,
|
|
294
|
+
pbIdentifier: input.pbIdentifier,
|
|
295
|
+
supabaseIdentifiers: input.supabaseIdentifiers,
|
|
296
|
+
});
|
|
297
|
+
let build;
|
|
298
|
+
if (input.build === true) {
|
|
299
|
+
build = await runProjectBuild(rootAbs);
|
|
300
|
+
}
|
|
301
|
+
const checklist = renderMigrationChecklist(analysis.checks);
|
|
302
|
+
const failing = analysis.checks.filter((c) => c.status === "fail");
|
|
303
|
+
const warning = analysis.checks.filter((c) => c.status === "warn");
|
|
304
|
+
const buildFailed = build?.ran === true && !build.passed;
|
|
305
|
+
const allGreen = failing.length === 0 && warning.length === 0 && !buildFailed;
|
|
306
|
+
const recovery = allGreen
|
|
307
|
+
? recoveryNone()
|
|
308
|
+
: recoveryAsk({
|
|
309
|
+
prompt: buildPrompt(analysis.state, failing, warning, build),
|
|
310
|
+
reasonCode: "unknown",
|
|
311
|
+
});
|
|
312
|
+
const summary = `${STATE_SUMMARY[analysis.state]}${build ? ` Build: ${build.ran ? (build.passed ? "passed" : "FAILED") : "skipped"}.` : ""}`;
|
|
313
|
+
return {
|
|
314
|
+
status: "ok",
|
|
315
|
+
rootDir: rootAbs,
|
|
316
|
+
state: analysis.state,
|
|
317
|
+
migrationComplete: analysis.migrationComplete,
|
|
318
|
+
checks: analysis.checks,
|
|
319
|
+
...(build ? { build } : {}),
|
|
320
|
+
recovery,
|
|
321
|
+
summary,
|
|
322
|
+
checklist,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function buildPrompt(state, failing, warning, build) {
|
|
326
|
+
const bits = [];
|
|
327
|
+
if (failing.length > 0) {
|
|
328
|
+
bits.push(`fix first: ${failing.map((c) => `${c.label} — ${c.detail}`).join("; ")}`);
|
|
329
|
+
}
|
|
330
|
+
if (warning.length > 0) {
|
|
331
|
+
bits.push(`still to do: ${warning.map((c) => `${c.label} (${c.count || "n/a"})`).join(", ")}`);
|
|
332
|
+
}
|
|
333
|
+
if (build?.ran && !build.passed) {
|
|
334
|
+
bits.push(`the build failed: ${build.detail}`);
|
|
335
|
+
}
|
|
336
|
+
const lead = state === "broken" ? "The migration is in a broken state." : "The migration isn't finished.";
|
|
337
|
+
return `${lead} ${bits.join(". ")}. Work through migration-preview/REWRITE_NOTES.md, then re-run --status.`;
|
|
338
|
+
}
|
|
339
|
+
/** Read migration-preview/MIGRATION_NOTES.md and pull the manual-RLS count
|
|
340
|
+
* from its stable summary line. Null when the file isn't present. */
|
|
341
|
+
async function readManualRlsCount(rootAbs) {
|
|
342
|
+
for (const dir of ["migration-preview", "."]) {
|
|
343
|
+
try {
|
|
344
|
+
const notes = await readFile(join(rootAbs, dir, "MIGRATION_NOTES.md"), "utf8");
|
|
345
|
+
const m = notes.match(/\*\*RLS policies:\*\*\s*\d+\s*\((\d+)\s*need manual review\)/);
|
|
346
|
+
if (m?.[1] !== undefined)
|
|
347
|
+
return Number.parseInt(m[1], 10);
|
|
348
|
+
return 0; // file present but no RLS line — treat as zero
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
// not in this dir — try the next
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Opt-in build gate. Detects the package manager from the lockfile and runs
|
|
358
|
+
* its `build` script, capturing exit code + a tail of output. Best-effort:
|
|
359
|
+
* a missing build script or absent node_modules surfaces as a failed/ skipped
|
|
360
|
+
* gate, never throws.
|
|
361
|
+
*/
|
|
362
|
+
async function runProjectBuild(rootAbs) {
|
|
363
|
+
let hasBuildScript = false;
|
|
364
|
+
try {
|
|
365
|
+
const pkg = JSON.parse(await readFile(join(rootAbs, "package.json"), "utf8"));
|
|
366
|
+
hasBuildScript = typeof pkg.scripts?.build === "string";
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
return { ran: false, passed: false, detail: "No readable package.json — nothing to build." };
|
|
370
|
+
}
|
|
371
|
+
if (!hasBuildScript) {
|
|
372
|
+
return { ran: false, passed: false, detail: "No `build` script in package.json." };
|
|
373
|
+
}
|
|
374
|
+
const pm = await detectPackageManager(rootAbs);
|
|
375
|
+
const result = await spawnCapture(pm, ["run", "build"], rootAbs, 300_000);
|
|
376
|
+
if (result.timedOut) {
|
|
377
|
+
return { ran: true, passed: false, detail: `\`${pm} run build\` timed out after 5 min.` };
|
|
378
|
+
}
|
|
379
|
+
if (result.spawnError) {
|
|
380
|
+
return {
|
|
381
|
+
ran: false,
|
|
382
|
+
passed: false,
|
|
383
|
+
detail: `Couldn't run \`${pm} run build\` (${result.spawnError}). Is ${pm} installed?`,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
const passed = result.code === 0;
|
|
387
|
+
const tail = lastLines(result.output, 12);
|
|
388
|
+
return {
|
|
389
|
+
ran: true,
|
|
390
|
+
passed,
|
|
391
|
+
detail: passed
|
|
392
|
+
? `\`${pm} run build\` succeeded.`
|
|
393
|
+
: `\`${pm} run build\` exited ${result.code}.${tail ? `\n${tail}` : ""}`,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
async function detectPackageManager(rootAbs) {
|
|
397
|
+
const has = async (name) => {
|
|
398
|
+
try {
|
|
399
|
+
await readFile(join(rootAbs, name), "utf8");
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
if ((await has("bun.lock")) || (await has("bun.lockb")))
|
|
407
|
+
return "bun";
|
|
408
|
+
if (await has("pnpm-lock.yaml"))
|
|
409
|
+
return "pnpm";
|
|
410
|
+
if (await has("yarn.lock"))
|
|
411
|
+
return "yarn";
|
|
412
|
+
return "npm";
|
|
413
|
+
}
|
|
414
|
+
/** Spawn via cross-spawn (Windows .cmd-shim safe, no shell), capture combined
|
|
415
|
+
* output, enforce a timeout. */
|
|
416
|
+
function spawnCapture(cmd, args, cwd, timeoutMs) {
|
|
417
|
+
return new Promise((resolve) => {
|
|
418
|
+
const child = crossSpawn(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
419
|
+
let output = "";
|
|
420
|
+
const onData = (chunk) => {
|
|
421
|
+
output += chunk.toString();
|
|
422
|
+
// Cap retained output so a chatty build doesn't balloon memory.
|
|
423
|
+
if (output.length > 64_000)
|
|
424
|
+
output = output.slice(-64_000);
|
|
425
|
+
};
|
|
426
|
+
child.stdout?.on("data", onData);
|
|
427
|
+
child.stderr?.on("data", onData);
|
|
428
|
+
let timedOut = false;
|
|
429
|
+
const timer = setTimeout(() => {
|
|
430
|
+
timedOut = true;
|
|
431
|
+
child.kill("SIGTERM");
|
|
432
|
+
}, timeoutMs);
|
|
433
|
+
child.on("error", (err) => {
|
|
434
|
+
clearTimeout(timer);
|
|
435
|
+
resolve({ code: 1, output, timedOut, spawnError: err.message });
|
|
436
|
+
});
|
|
437
|
+
child.on("close", (code) => {
|
|
438
|
+
clearTimeout(timer);
|
|
439
|
+
resolve({ code: code ?? 1, output, timedOut });
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
function lastLines(text, n) {
|
|
444
|
+
const lines = text.split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
445
|
+
return lines.slice(-n).join("\n");
|
|
446
|
+
}
|
|
447
|
+
function failure(rootAbs, err) {
|
|
448
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
449
|
+
return {
|
|
450
|
+
status: "failed",
|
|
451
|
+
rootDir: rootAbs,
|
|
452
|
+
state: "broken",
|
|
453
|
+
migrationComplete: false,
|
|
454
|
+
checks: [],
|
|
455
|
+
recovery: recoveryAsk({
|
|
456
|
+
prompt: `Couldn't scan the project for migration status (${message}). Check the path exists and is readable, then re-run.`,
|
|
457
|
+
reasonCode: "unknown",
|
|
458
|
+
retryable: true,
|
|
459
|
+
}),
|
|
460
|
+
summary: `Migration status scan failed: ${message}`,
|
|
461
|
+
checklist: "",
|
|
462
|
+
error: {
|
|
463
|
+
code: "status_failed",
|
|
464
|
+
title: "Migration status scan failed",
|
|
465
|
+
explanation: message,
|
|
466
|
+
suggestion: "Check the project path exists and is readable, then re-run.",
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
//# sourceMappingURL=migrate-supabase-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-supabase-status.js","sourceRoot":"","sources":["../../src/commands/migrate-supabase-status.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RewriteFlag } from "./migrate-supabase-sdk";
|
|
1
|
+
import { type RewriteFlag } from "./migrate-supabase-sdk.js";
|
|
2
2
|
export type WalkedFileKind = "code" | "package_json" | "env";
|
|
3
3
|
export interface WalkedFile {
|
|
4
4
|
/** Path relative to `rootDir`, forward-slash-normalised. */
|
|
@@ -42,6 +42,20 @@ export interface WalkSupabaseProjectResult {
|
|
|
42
42
|
flagCount: number;
|
|
43
43
|
packageJsonChanged: boolean;
|
|
44
44
|
envFilesChanged: number;
|
|
45
|
+
/**
|
|
46
|
+
* True when nothing Supabase remains after the rewrite — zero
|
|
47
|
+
* `@supabase/*` imports AND zero remaining auth/storage/rpc/realtime/
|
|
48
|
+
* edge-function calls. Only then is dropping the dep + stubbing the
|
|
49
|
+
* env safe. A hybrid project (some calls left untouched on purpose)
|
|
50
|
+
* reports false, and the walker keeps the Supabase dep + env intact.
|
|
51
|
+
*/
|
|
52
|
+
migrationComplete: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Count behind `migrationComplete`: remaining auth/storage/rpc/realtime/
|
|
55
|
+
* edge calls plus files still importing `@supabase/*`. Surfaced so the
|
|
56
|
+
* caller can explain WHY the dep/env were kept.
|
|
57
|
+
*/
|
|
58
|
+
supabaseUsageRemaining: number;
|
|
45
59
|
};
|
|
46
60
|
}
|
|
47
61
|
export declare function walkSupabaseProject(input: WalkSupabaseProjectInput): Promise<WalkSupabaseProjectResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-supabase-walker.d.ts","sourceRoot":"","sources":["../../src/commands/migrate-supabase-walker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"migrate-supabase-walker.d.ts","sourceRoot":"","sources":["../../src/commands/migrate-supabase-walker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAyC,MAAM,wBAAwB,CAAC;AAuDjG,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,cAAc,GAAG,KAAK,CAAC;AAE7D,MAAM,WAAW,UAAU;IACzB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,IAAI,EAAE,cAAc,CAAC;IACrB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,4EAA4E;IAC5E,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,uCAAuC;IACvC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;QACxB;;;;;;WAMG;QACH,iBAAiB,EAAE,OAAO,CAAC;QAC3B;;;;WAIG;QACH,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC;CACH;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,yBAAyB,CAAC,CA+JpC;AA8DD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB,CAgDA;AAID;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB,CAgEA;AA8BD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,yBAAyB,CAAC;IAClC,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAsCjG"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
3
|
import ignore from "ignore";
|
|
4
|
-
import { rewriteSupabaseSdk } from "./migrate-supabase-sdk";
|
|
4
|
+
import { rewriteSupabaseSdk, scanSupabaseUsage } from "./migrate-supabase-sdk.js";
|
|
5
5
|
/**
|
|
6
6
|
* FUTURE9 Phase D chunk 3.2 — project-wide Supabase rewrite.
|
|
7
7
|
*
|
|
@@ -60,6 +60,12 @@ export async function walkSupabaseProject(input) {
|
|
|
60
60
|
}
|
|
61
61
|
const files = [];
|
|
62
62
|
const skipped = [];
|
|
63
|
+
// Config files (package.json / .env*) are held until the code-file scan
|
|
64
|
+
// tells us whether the migration is complete — dropping the Supabase dep
|
|
65
|
+
// or stubbing the env while untouched Supabase calls remain breaks a
|
|
66
|
+
// hybrid app. Rewriting them per-file in the loop (the old behaviour)
|
|
67
|
+
// couldn't see the project-wide picture.
|
|
68
|
+
const pendingConfig = [];
|
|
63
69
|
for await (const absPath of walkTree(rootAbs, rootAbs, ig)) {
|
|
64
70
|
const rel = relative(rootAbs, absPath).split(sep).join("/");
|
|
65
71
|
const kind = classifyFile(rel);
|
|
@@ -118,11 +124,47 @@ export async function walkSupabaseProject(input) {
|
|
|
118
124
|
});
|
|
119
125
|
continue;
|
|
120
126
|
}
|
|
121
|
-
|
|
127
|
+
// Hold config files — rewrite them only after the migration-complete
|
|
128
|
+
// decision below.
|
|
129
|
+
pendingConfig.push({ relativePath: rel, kind, source });
|
|
130
|
+
}
|
|
131
|
+
// Decide migration-complete from the REWRITTEN code files: scan each for
|
|
132
|
+
// any Supabase surface that would survive the rewrite. The dep/env are
|
|
133
|
+
// only safe to drop when nothing is left.
|
|
134
|
+
let supabaseUsageRemaining = 0;
|
|
135
|
+
for (const file of files) {
|
|
136
|
+
if (file.kind !== "code")
|
|
137
|
+
continue;
|
|
138
|
+
const scan = scanSupabaseUsage({
|
|
139
|
+
source: file.rewritten,
|
|
140
|
+
supabaseIdentifiers: input.supabaseIdentifiers,
|
|
141
|
+
});
|
|
142
|
+
supabaseUsageRemaining +=
|
|
143
|
+
scan.authCalls + scan.storage + scan.rpc + scan.realtime + scan.edgeFunctions;
|
|
144
|
+
if (scan.importsSupabase)
|
|
145
|
+
supabaseUsageRemaining += 1;
|
|
146
|
+
}
|
|
147
|
+
const migrationComplete = supabaseUsageRemaining === 0;
|
|
148
|
+
// Apply the held config rewrites only when the migration is complete.
|
|
149
|
+
// Otherwise keep them byte-for-byte (the hybrid app still needs the
|
|
150
|
+
// Supabase dep + env); the caller surfaces the "kept on purpose" note.
|
|
151
|
+
for (const cfg of pendingConfig) {
|
|
152
|
+
if (!migrationComplete) {
|
|
153
|
+
files.push({
|
|
154
|
+
relativePath: cfg.relativePath,
|
|
155
|
+
kind: cfg.kind,
|
|
156
|
+
source: cfg.source,
|
|
157
|
+
rewritten: cfg.source,
|
|
158
|
+
changed: false,
|
|
159
|
+
flags: [],
|
|
160
|
+
});
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const configResult = cfg.kind === "package_json" ? rewritePackageJson(cfg.source) : rewriteEnvFile(cfg.source);
|
|
122
164
|
files.push({
|
|
123
|
-
relativePath:
|
|
124
|
-
kind,
|
|
125
|
-
source,
|
|
165
|
+
relativePath: cfg.relativePath,
|
|
166
|
+
kind: cfg.kind,
|
|
167
|
+
source: cfg.source,
|
|
126
168
|
rewritten: configResult.rewritten,
|
|
127
169
|
changed: configResult.changed,
|
|
128
170
|
flags: configResult.flags,
|
|
@@ -156,6 +198,8 @@ export async function walkSupabaseProject(input) {
|
|
|
156
198
|
flagCount,
|
|
157
199
|
packageJsonChanged,
|
|
158
200
|
envFilesChanged,
|
|
201
|
+
migrationComplete,
|
|
202
|
+
supabaseUsageRemaining,
|
|
159
203
|
},
|
|
160
204
|
};
|
|
161
205
|
}
|