@tiangong-lca/cli 0.0.21 → 0.0.23

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.
@@ -0,0 +1,295 @@
1
+ import { CliError } from './errors.js';
2
+ import { buildSnapshotCompleteness, fetchCompletePostgrestPages, } from './dataset-maintenance-pagination.js';
3
+ import { buildSupabaseAuthHeaders, deriveSupabaseProjectBaseUrl, requireSupabaseRestRuntime, } from './supabase-client.js';
4
+ import { resolveSupabaseUserSession } from './supabase-session.js';
5
+ import { isJsonObject, MAINTENANCE_SCAN_TABLES, } from './dataset-maintenance-contract.js';
6
+ const DEFAULT_PAGE_SIZE = 1_000;
7
+ const DEFAULT_TIMEOUT_MS = 10_000;
8
+ function trimToken(value) {
9
+ if (typeof value !== 'string') {
10
+ return null;
11
+ }
12
+ const trimmed = value.trim();
13
+ return trimmed || null;
14
+ }
15
+ function normalizeStateCode(value) {
16
+ if (typeof value === 'number' && Number.isInteger(value)) {
17
+ return value;
18
+ }
19
+ return typeof value === 'string' && /^-?\d+$/u.test(value.trim())
20
+ ? Number.parseInt(value.trim(), 10)
21
+ : null;
22
+ }
23
+ export function normalizeMaintenancePageSize(value) {
24
+ const normalized = value ?? DEFAULT_PAGE_SIZE;
25
+ if (!Number.isInteger(normalized) || normalized < 1 || normalized > 5_000) {
26
+ throw new CliError('Maintenance page size must be an integer between 1 and 5000.', {
27
+ code: 'DATASET_MAINTENANCE_PAGE_SIZE_INVALID',
28
+ exitCode: 2,
29
+ details: value,
30
+ });
31
+ }
32
+ return normalized;
33
+ }
34
+ export function normalizeMaintenanceTimeout(value) {
35
+ const normalized = value ?? DEFAULT_TIMEOUT_MS;
36
+ if (!Number.isInteger(normalized) || normalized < 1) {
37
+ throw new CliError('Maintenance timeout must be a positive integer.', {
38
+ code: 'DATASET_MAINTENANCE_TIMEOUT_INVALID',
39
+ exitCode: 2,
40
+ details: value,
41
+ });
42
+ }
43
+ return normalized;
44
+ }
45
+ async function fetchJsonResponse(options) {
46
+ const response = await options.context.fetch_impl(options.url, {
47
+ ...options.init,
48
+ headers: {
49
+ ...buildSupabaseAuthHeaders(options.context.publishable_key, options.context.access_token),
50
+ ...(options.init?.headers ?? {}),
51
+ },
52
+ signal: AbortSignal.timeout(options.context.timeout_ms),
53
+ });
54
+ const text = await response.text();
55
+ if (!response.ok) {
56
+ throw new CliError(`HTTP ${response.status} returned from ${options.label}`, {
57
+ code: 'DATASET_MAINTENANCE_REMOTE_REQUEST_FAILED',
58
+ exitCode: 1,
59
+ details: { url: options.url, response: text },
60
+ });
61
+ }
62
+ if (!text.trim()) {
63
+ return { body: null, headers: response.headers };
64
+ }
65
+ try {
66
+ return { body: JSON.parse(text), headers: response.headers };
67
+ }
68
+ catch (error) {
69
+ throw new CliError(`Remote response was not valid JSON for ${options.label}`, {
70
+ code: 'DATASET_MAINTENANCE_REMOTE_INVALID_JSON',
71
+ exitCode: 1,
72
+ details: {
73
+ url: options.url,
74
+ error: String(error),
75
+ },
76
+ });
77
+ }
78
+ }
79
+ async function fetchJson(options) {
80
+ return (await fetchJsonResponse(options)).body;
81
+ }
82
+ function selectForTable(table) {
83
+ const common = 'id,version,user_id,state_code,modified_at,json_ordered,rule_verification';
84
+ return table === 'processes' ? `${common},model_id` : common;
85
+ }
86
+ function normalizeRemoteRow(table, value) {
87
+ if (!isJsonObject(value)) {
88
+ return null;
89
+ }
90
+ const id = trimToken(value.id);
91
+ const version = trimToken(value.version);
92
+ if (!id || !version) {
93
+ return null;
94
+ }
95
+ return {
96
+ table,
97
+ id,
98
+ version,
99
+ user_id: trimToken(value.user_id),
100
+ state_code: normalizeStateCode(value.state_code),
101
+ modified_at: trimToken(value.modified_at),
102
+ json_ordered: isJsonObject(value.json_ordered) ? value.json_ordered : null,
103
+ model_id: trimToken(value.model_id),
104
+ rule_verification: typeof value.rule_verification === 'boolean' ? value.rule_verification : null,
105
+ };
106
+ }
107
+ function normalizeRemoteRows(table, value, label) {
108
+ if (!Array.isArray(value)) {
109
+ throw new CliError(`Remote response was not an array for ${label}.`, {
110
+ code: 'DATASET_MAINTENANCE_REMOTE_ROWS_INVALID',
111
+ exitCode: 1,
112
+ details: value,
113
+ });
114
+ }
115
+ const rows = value.map((entry) => normalizeRemoteRow(table, entry));
116
+ if (rows.some((row) => row === null)) {
117
+ throw new CliError(`Remote response contained an invalid row for ${label}.`, {
118
+ code: 'DATASET_MAINTENANCE_REMOTE_ROW_INVALID',
119
+ exitCode: 1,
120
+ });
121
+ }
122
+ return rows;
123
+ }
124
+ export async function resolveMaintenanceRemoteContext(options) {
125
+ const timeoutMs = normalizeMaintenanceTimeout(options.timeoutMs);
126
+ const runtime = requireSupabaseRestRuntime(options.env);
127
+ const session = await resolveSupabaseUserSession({
128
+ runtime,
129
+ fetchImpl: options.fetchImpl,
130
+ timeoutMs,
131
+ now: options.now,
132
+ });
133
+ const projectBaseUrl = deriveSupabaseProjectBaseUrl(runtime.apiBaseUrl);
134
+ const partialContext = {
135
+ publishable_key: runtime.publishableKey,
136
+ access_token: session.accessToken,
137
+ fetch_impl: options.fetchImpl,
138
+ timeout_ms: timeoutMs,
139
+ };
140
+ const currentUser = await fetchJson({
141
+ context: partialContext,
142
+ url: `${projectBaseUrl}/auth/v1/user`,
143
+ label: 'supabase current-user lookup',
144
+ });
145
+ const userId = isJsonObject(currentUser) ? trimToken(currentUser.id) : null;
146
+ const email = isJsonObject(currentUser)
147
+ ? (trimToken(currentUser.email) ?? trimToken(session.userEmail))
148
+ : trimToken(session.userEmail);
149
+ if (!userId || !email) {
150
+ throw new CliError('Supabase current-user lookup did not return id and email.', {
151
+ code: 'DATASET_MAINTENANCE_CURRENT_USER_INVALID',
152
+ exitCode: 1,
153
+ });
154
+ }
155
+ return {
156
+ rest_base_url: `${projectBaseUrl}/rest/v1`,
157
+ publishable_key: runtime.publishableKey,
158
+ access_token: session.accessToken,
159
+ account: {
160
+ user_id: userId,
161
+ email,
162
+ session_source: session.source,
163
+ },
164
+ fetch_impl: options.fetchImpl,
165
+ timeout_ms: timeoutMs,
166
+ };
167
+ }
168
+ export async function fetchMaintenanceExactRows(options) {
169
+ const url = new URL(`${options.context.rest_base_url}/${options.table}`);
170
+ url.searchParams.set('select', selectForTable(options.table));
171
+ url.searchParams.set('id', `eq.${options.id}`);
172
+ url.searchParams.set('version', `eq.${options.version}`);
173
+ url.searchParams.set('limit', '2');
174
+ const sourceUrl = url.toString();
175
+ const body = await fetchJson({
176
+ context: options.context,
177
+ url: sourceUrl,
178
+ label: `${options.table} exact maintenance lookup`,
179
+ });
180
+ return {
181
+ rows: normalizeRemoteRows(options.table, body, sourceUrl),
182
+ source_url: sourceUrl,
183
+ };
184
+ }
185
+ export async function fetchMaintenanceAccountRows(options) {
186
+ const pageSize = normalizeMaintenancePageSize(options.pageSize);
187
+ const tableResults = [];
188
+ for (const table of MAINTENANCE_SCAN_TABLES) {
189
+ const result = await fetchCompletePostgrestPages({
190
+ table,
191
+ requestedPageSize: pageSize,
192
+ rowIdentity: (row) => `${row.id}\u0000${row.version}`,
193
+ fetchPage: async (offset) => {
194
+ const url = new URL(`${options.context.rest_base_url}/${table}`);
195
+ url.searchParams.set('select', selectForTable(table));
196
+ url.searchParams.set('user_id', `eq.${options.userId}`);
197
+ url.searchParams.set('order', 'id.asc,version.asc');
198
+ url.searchParams.set('limit', String(pageSize));
199
+ url.searchParams.set('offset', String(offset));
200
+ const sourceUrl = url.toString();
201
+ const response = await fetchJsonResponse({
202
+ context: options.context,
203
+ url: sourceUrl,
204
+ init: { headers: { Prefer: 'count=exact' } },
205
+ label: `${table} account maintenance snapshot`,
206
+ });
207
+ const rows = normalizeRemoteRows(table, response.body, sourceUrl);
208
+ if (rows.some((row) => row.user_id !== options.userId)) {
209
+ throw new CliError(`Remote ${table} snapshot contained a foreign account row.`, {
210
+ code: 'DATASET_MAINTENANCE_REMOTE_ROW_INVALID',
211
+ exitCode: 1,
212
+ });
213
+ }
214
+ return {
215
+ rows,
216
+ source_url: sourceUrl,
217
+ content_range: response.headers.get('content-range'),
218
+ };
219
+ },
220
+ });
221
+ tableResults.push({ table, ...result });
222
+ }
223
+ return {
224
+ rows: tableResults.flatMap((result) => result.rows),
225
+ source_urls: tableResults.flatMap((result) => result.source_urls),
226
+ completeness: buildSnapshotCompleteness({
227
+ tables: MAINTENANCE_SCAN_TABLES,
228
+ requestedPageSize: pageSize,
229
+ results: tableResults,
230
+ }),
231
+ };
232
+ }
233
+ async function invokeMaintenanceRpc(options) {
234
+ const url = `${options.context.rest_base_url}/rpc/${options.rpc}`;
235
+ const body = await fetchJson({
236
+ context: options.context,
237
+ url,
238
+ init: {
239
+ method: 'POST',
240
+ headers: { 'Content-Type': 'application/json' },
241
+ body: JSON.stringify(options.body),
242
+ },
243
+ label: options.rpc,
244
+ });
245
+ if (!isJsonObject(body) || body.ok !== true) {
246
+ throw new CliError(`${options.rpc} returned an unexpected response.`, {
247
+ code: 'DATASET_MAINTENANCE_RPC_FAILED',
248
+ exitCode: 1,
249
+ details: body,
250
+ });
251
+ }
252
+ return body;
253
+ }
254
+ export async function applyMaintenanceAliasPlan(options) {
255
+ return invokeMaintenanceRpc({
256
+ context: options.context,
257
+ rpc: 'cmd_dataset_alias_plan_guarded',
258
+ body: { p_plan: options.plan },
259
+ });
260
+ }
261
+ export async function saveDraftMaintenanceRow(options) {
262
+ return invokeMaintenanceRpc({
263
+ context: options.context,
264
+ rpc: 'cmd_dataset_save_draft',
265
+ body: {
266
+ p_table: options.table,
267
+ p_id: options.id,
268
+ p_version: options.version,
269
+ p_json_ordered: options.payload,
270
+ p_model_id: options.modelId,
271
+ p_rule_verification: options.ruleVerification,
272
+ p_audit: options.audit,
273
+ },
274
+ });
275
+ }
276
+ export async function deleteMaintenanceRow(options) {
277
+ return invokeMaintenanceRpc({
278
+ context: options.context,
279
+ rpc: 'cmd_dataset_delete',
280
+ body: {
281
+ p_table: options.table,
282
+ p_id: options.id,
283
+ p_version: options.version,
284
+ p_audit: options.audit,
285
+ },
286
+ });
287
+ }
288
+ export const __testInternals = {
289
+ fetchJson,
290
+ fetchJsonResponse,
291
+ normalizeRemoteRow,
292
+ normalizeRemoteRows,
293
+ selectForTable,
294
+ };
295
+ //# sourceMappingURL=dataset-maintenance-remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-maintenance-remote.js","sourceRoot":"","sources":["../../../src/lib/dataset-maintenance-remote.ts"],"names":[],"mappings":"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","sourcesContent":["import { CliError } from './errors.js';\nimport type { FetchLike, ResponseLike } from './http.js';\nimport {\n buildSnapshotCompleteness,\n fetchCompletePostgrestPages,\n type DatasetMaintenanceSnapshotCompleteness,\n} from './dataset-maintenance-pagination.js';\nimport {\n buildSupabaseAuthHeaders,\n deriveSupabaseProjectBaseUrl,\n requireSupabaseRestRuntime,\n} from './supabase-client.js';\nimport { resolveSupabaseUserSession } from './supabase-session.js';\nimport {\n isJsonObject,\n MAINTENANCE_SCAN_TABLES,\n type DatasetMaintenanceMutableTable,\n type DatasetMaintenanceRemoteRow,\n type DatasetMaintenanceScanTable,\n type JsonObject,\n} from './dataset-maintenance-contract.js';\n\nconst DEFAULT_PAGE_SIZE = 1_000;\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport type DatasetMaintenanceRemoteContext = {\n rest_base_url: string;\n publishable_key: string;\n access_token: string;\n account: {\n user_id: string;\n email: string;\n session_source: string;\n };\n fetch_impl: FetchLike;\n timeout_ms: number;\n};\n\nfunction trimToken(value: unknown): string | null {\n if (typeof value !== 'string') {\n return null;\n }\n const trimmed = value.trim();\n return trimmed || null;\n}\n\nfunction normalizeStateCode(value: unknown): number | null {\n if (typeof value === 'number' && Number.isInteger(value)) {\n return value;\n }\n return typeof value === 'string' && /^-?\\d+$/u.test(value.trim())\n ? Number.parseInt(value.trim(), 10)\n : null;\n}\n\nexport function normalizeMaintenancePageSize(value?: number): number {\n const normalized = value ?? DEFAULT_PAGE_SIZE;\n if (!Number.isInteger(normalized) || normalized < 1 || normalized > 5_000) {\n throw new CliError('Maintenance page size must be an integer between 1 and 5000.', {\n code: 'DATASET_MAINTENANCE_PAGE_SIZE_INVALID',\n exitCode: 2,\n details: value,\n });\n }\n return normalized;\n}\n\nexport function normalizeMaintenanceTimeout(value?: number): number {\n const normalized = value ?? DEFAULT_TIMEOUT_MS;\n if (!Number.isInteger(normalized) || normalized < 1) {\n throw new CliError('Maintenance timeout must be a positive integer.', {\n code: 'DATASET_MAINTENANCE_TIMEOUT_INVALID',\n exitCode: 2,\n details: value,\n });\n }\n return normalized;\n}\n\nasync function fetchJsonResponse(options: {\n context: Pick<\n DatasetMaintenanceRemoteContext,\n 'publishable_key' | 'access_token' | 'fetch_impl' | 'timeout_ms'\n >;\n url: string;\n init?: RequestInit;\n label: string;\n}): Promise<{ body: unknown; headers: ResponseLike['headers'] }> {\n const response = await options.context.fetch_impl(options.url, {\n ...options.init,\n headers: {\n ...buildSupabaseAuthHeaders(options.context.publishable_key, options.context.access_token),\n ...(options.init?.headers ?? {}),\n },\n signal: AbortSignal.timeout(options.context.timeout_ms),\n });\n const text = await response.text();\n if (!response.ok) {\n throw new CliError(`HTTP ${response.status} returned from ${options.label}`, {\n code: 'DATASET_MAINTENANCE_REMOTE_REQUEST_FAILED',\n exitCode: 1,\n details: { url: options.url, response: text },\n });\n }\n if (!text.trim()) {\n return { body: null, headers: response.headers };\n }\n try {\n return { body: JSON.parse(text), headers: response.headers };\n } catch (error) {\n throw new CliError(`Remote response was not valid JSON for ${options.label}`, {\n code: 'DATASET_MAINTENANCE_REMOTE_INVALID_JSON',\n exitCode: 1,\n details: {\n url: options.url,\n error: String(error),\n },\n });\n }\n}\n\nasync function fetchJson(options: {\n context: Pick<\n DatasetMaintenanceRemoteContext,\n 'publishable_key' | 'access_token' | 'fetch_impl' | 'timeout_ms'\n >;\n url: string;\n init?: RequestInit;\n label: string;\n}): Promise<unknown> {\n return (await fetchJsonResponse(options)).body;\n}\n\nfunction selectForTable(table: DatasetMaintenanceScanTable): string {\n const common = 'id,version,user_id,state_code,modified_at,json_ordered,rule_verification';\n return table === 'processes' ? `${common},model_id` : common;\n}\n\nfunction normalizeRemoteRow(\n table: DatasetMaintenanceScanTable,\n value: unknown,\n): DatasetMaintenanceRemoteRow | null {\n if (!isJsonObject(value)) {\n return null;\n }\n const id = trimToken(value.id);\n const version = trimToken(value.version);\n if (!id || !version) {\n return null;\n }\n return {\n table,\n id,\n version,\n user_id: trimToken(value.user_id),\n state_code: normalizeStateCode(value.state_code),\n modified_at: trimToken(value.modified_at),\n json_ordered: isJsonObject(value.json_ordered) ? value.json_ordered : null,\n model_id: trimToken(value.model_id),\n rule_verification:\n typeof value.rule_verification === 'boolean' ? value.rule_verification : null,\n };\n}\n\nfunction normalizeRemoteRows(\n table: DatasetMaintenanceScanTable,\n value: unknown,\n label: string,\n): DatasetMaintenanceRemoteRow[] {\n if (!Array.isArray(value)) {\n throw new CliError(`Remote response was not an array for ${label}.`, {\n code: 'DATASET_MAINTENANCE_REMOTE_ROWS_INVALID',\n exitCode: 1,\n details: value,\n });\n }\n const rows = value.map((entry) => normalizeRemoteRow(table, entry));\n if (rows.some((row) => row === null)) {\n throw new CliError(`Remote response contained an invalid row for ${label}.`, {\n code: 'DATASET_MAINTENANCE_REMOTE_ROW_INVALID',\n exitCode: 1,\n });\n }\n return rows as DatasetMaintenanceRemoteRow[];\n}\n\nexport async function resolveMaintenanceRemoteContext(options: {\n env: NodeJS.ProcessEnv;\n fetchImpl: FetchLike;\n timeoutMs?: number;\n now?: Date;\n}): Promise<DatasetMaintenanceRemoteContext> {\n const timeoutMs = normalizeMaintenanceTimeout(options.timeoutMs);\n const runtime = requireSupabaseRestRuntime(options.env);\n const session = await resolveSupabaseUserSession({\n runtime,\n fetchImpl: options.fetchImpl,\n timeoutMs,\n now: options.now,\n });\n const projectBaseUrl = deriveSupabaseProjectBaseUrl(runtime.apiBaseUrl);\n const partialContext = {\n publishable_key: runtime.publishableKey,\n access_token: session.accessToken,\n fetch_impl: options.fetchImpl,\n timeout_ms: timeoutMs,\n };\n const currentUser = await fetchJson({\n context: partialContext,\n url: `${projectBaseUrl}/auth/v1/user`,\n label: 'supabase current-user lookup',\n });\n const userId = isJsonObject(currentUser) ? trimToken(currentUser.id) : null;\n const email = isJsonObject(currentUser)\n ? (trimToken(currentUser.email) ?? trimToken(session.userEmail))\n : trimToken(session.userEmail);\n if (!userId || !email) {\n throw new CliError('Supabase current-user lookup did not return id and email.', {\n code: 'DATASET_MAINTENANCE_CURRENT_USER_INVALID',\n exitCode: 1,\n });\n }\n return {\n rest_base_url: `${projectBaseUrl}/rest/v1`,\n publishable_key: runtime.publishableKey,\n access_token: session.accessToken,\n account: {\n user_id: userId,\n email,\n session_source: session.source,\n },\n fetch_impl: options.fetchImpl,\n timeout_ms: timeoutMs,\n };\n}\n\nexport async function fetchMaintenanceExactRows(options: {\n context: DatasetMaintenanceRemoteContext;\n table: DatasetMaintenanceScanTable;\n id: string;\n version: string;\n}): Promise<{ rows: DatasetMaintenanceRemoteRow[]; source_url: string }> {\n const url = new URL(`${options.context.rest_base_url}/${options.table}`);\n url.searchParams.set('select', selectForTable(options.table));\n url.searchParams.set('id', `eq.${options.id}`);\n url.searchParams.set('version', `eq.${options.version}`);\n url.searchParams.set('limit', '2');\n const sourceUrl = url.toString();\n const body = await fetchJson({\n context: options.context,\n url: sourceUrl,\n label: `${options.table} exact maintenance lookup`,\n });\n return {\n rows: normalizeRemoteRows(options.table, body, sourceUrl),\n source_url: sourceUrl,\n };\n}\n\nexport async function fetchMaintenanceAccountRows(options: {\n context: DatasetMaintenanceRemoteContext;\n userId: string;\n pageSize?: number;\n}): Promise<{\n rows: DatasetMaintenanceRemoteRow[];\n source_urls: string[];\n completeness: DatasetMaintenanceSnapshotCompleteness<DatasetMaintenanceScanTable>;\n}> {\n const pageSize = normalizeMaintenancePageSize(options.pageSize);\n const tableResults: Array<{\n table: DatasetMaintenanceScanTable;\n rows: DatasetMaintenanceRemoteRow[];\n source_urls: string[];\n completeness: Awaited<ReturnType<typeof fetchCompletePostgrestPages>>['completeness'];\n }> = [];\n for (const table of MAINTENANCE_SCAN_TABLES) {\n const result = await fetchCompletePostgrestPages({\n table,\n requestedPageSize: pageSize,\n rowIdentity: (row: DatasetMaintenanceRemoteRow) => `${row.id}\\u0000${row.version}`,\n fetchPage: async (offset) => {\n const url = new URL(`${options.context.rest_base_url}/${table}`);\n url.searchParams.set('select', selectForTable(table));\n url.searchParams.set('user_id', `eq.${options.userId}`);\n url.searchParams.set('order', 'id.asc,version.asc');\n url.searchParams.set('limit', String(pageSize));\n url.searchParams.set('offset', String(offset));\n const sourceUrl = url.toString();\n const response = await fetchJsonResponse({\n context: options.context,\n url: sourceUrl,\n init: { headers: { Prefer: 'count=exact' } },\n label: `${table} account maintenance snapshot`,\n });\n const rows = normalizeRemoteRows(table, response.body, sourceUrl);\n if (rows.some((row) => row.user_id !== options.userId)) {\n throw new CliError(`Remote ${table} snapshot contained a foreign account row.`, {\n code: 'DATASET_MAINTENANCE_REMOTE_ROW_INVALID',\n exitCode: 1,\n });\n }\n return {\n rows,\n source_url: sourceUrl,\n content_range: response.headers.get('content-range'),\n };\n },\n });\n tableResults.push({ table, ...result });\n }\n return {\n rows: tableResults.flatMap((result) => result.rows),\n source_urls: tableResults.flatMap((result) => result.source_urls),\n completeness: buildSnapshotCompleteness({\n tables: MAINTENANCE_SCAN_TABLES,\n requestedPageSize: pageSize,\n results: tableResults,\n }),\n };\n}\n\nasync function invokeMaintenanceRpc(options: {\n context: DatasetMaintenanceRemoteContext;\n rpc: 'cmd_dataset_save_draft' | 'cmd_dataset_delete' | 'cmd_dataset_alias_plan_guarded';\n body: JsonObject;\n}): Promise<JsonObject> {\n const url = `${options.context.rest_base_url}/rpc/${options.rpc}`;\n const body = await fetchJson({\n context: options.context,\n url,\n init: {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(options.body),\n },\n label: options.rpc,\n });\n if (!isJsonObject(body) || body.ok !== true) {\n throw new CliError(`${options.rpc} returned an unexpected response.`, {\n code: 'DATASET_MAINTENANCE_RPC_FAILED',\n exitCode: 1,\n details: body,\n });\n }\n return body;\n}\n\nexport async function applyMaintenanceAliasPlan(options: {\n context: DatasetMaintenanceRemoteContext;\n plan: JsonObject;\n}): Promise<JsonObject> {\n return invokeMaintenanceRpc({\n context: options.context,\n rpc: 'cmd_dataset_alias_plan_guarded',\n body: { p_plan: options.plan },\n });\n}\n\nexport async function saveDraftMaintenanceRow(options: {\n context: DatasetMaintenanceRemoteContext;\n table: DatasetMaintenanceMutableTable;\n id: string;\n version: string;\n payload: JsonObject;\n modelId: string | null;\n ruleVerification: boolean | null;\n audit: JsonObject;\n}): Promise<JsonObject> {\n return invokeMaintenanceRpc({\n context: options.context,\n rpc: 'cmd_dataset_save_draft',\n body: {\n p_table: options.table,\n p_id: options.id,\n p_version: options.version,\n p_json_ordered: options.payload,\n p_model_id: options.modelId,\n p_rule_verification: options.ruleVerification,\n p_audit: options.audit,\n },\n });\n}\n\nexport async function deleteMaintenanceRow(options: {\n context: DatasetMaintenanceRemoteContext;\n table: DatasetMaintenanceMutableTable;\n id: string;\n version: string;\n audit: JsonObject;\n}): Promise<JsonObject> {\n return invokeMaintenanceRpc({\n context: options.context,\n rpc: 'cmd_dataset_delete',\n body: {\n p_table: options.table,\n p_id: options.id,\n p_version: options.version,\n p_audit: options.audit,\n },\n });\n}\n\nexport const __testInternals = {\n fetchJson,\n fetchJsonResponse,\n normalizeRemoteRow,\n normalizeRemoteRows,\n selectForTable,\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import { FlowPropertySchema, UnitGroupSchema } from '@tiangong-lca/tidas-sdk';
2
+ import { collectRemoteReferences } from './dataset-remote-verify.js';
3
+ const DEFAULT_SUPPORT_SCHEMAS = {
4
+ unitgroups: UnitGroupSchema,
5
+ flowproperties: FlowPropertySchema,
6
+ };
7
+ export function maintenancePayloadIdentity(payload) {
8
+ const root = collectRemoteReferences([{ json_ordered: payload }]).find((reference) => reference.role === 'root');
9
+ return { id: root?.id ?? null, version: root?.version ?? null };
10
+ }
11
+ export function inspectMaintenanceSupportPayload(options) {
12
+ const schema = options.schemas?.[options.table] ?? DEFAULT_SUPPORT_SCHEMAS[options.table];
13
+ return {
14
+ identity: maintenancePayloadIdentity(options.payload),
15
+ schemaResult: schema.safeParse(options.payload),
16
+ };
17
+ }
18
+ //# sourceMappingURL=dataset-maintenance-support-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-maintenance-support-validation.js","sourceRoot":"","sources":["../../../src/lib/dataset-maintenance-support-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAQrE,MAAM,uBAAuB,GAA4D;IACvF,UAAU,EAAE,eAA6C;IACzD,cAAc,EAAE,kBAAgD;CACjE,CAAC;AAEF,MAAM,UAAU,0BAA0B,CAAC,OAAmB;IAI5D,MAAM,IAAI,GAAG,uBAAuB,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CACpE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,CACzC,CAAC;IACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,OAIhD;IAIC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,uBAAuB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1F,OAAO;QACL,QAAQ,EAAE,0BAA0B,CAAC,OAAO,CAAC,OAAO,CAAC;QACrD,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;KAChD,CAAC;AACJ,CAAC","sourcesContent":["import { FlowPropertySchema, UnitGroupSchema } from '@tiangong-lca/tidas-sdk';\nimport { collectRemoteReferences } from './dataset-remote-verify.js';\nimport type { DatasetMaintenanceSupportTable, JsonObject } from './dataset-maintenance-contract.js';\nimport type { SafeParseResult, SafeParseSchema } from './tidas-sdk-validation.js';\n\nexport type DatasetMaintenanceSupportSchemas = Partial<\n Record<DatasetMaintenanceSupportTable, SafeParseSchema>\n>;\n\nconst DEFAULT_SUPPORT_SCHEMAS: Record<DatasetMaintenanceSupportTable, SafeParseSchema> = {\n unitgroups: UnitGroupSchema as unknown as SafeParseSchema,\n flowproperties: FlowPropertySchema as unknown as SafeParseSchema,\n};\n\nexport function maintenancePayloadIdentity(payload: JsonObject): {\n id: string | null;\n version: string | null;\n} {\n const root = collectRemoteReferences([{ json_ordered: payload }]).find(\n (reference) => reference.role === 'root',\n );\n return { id: root?.id ?? null, version: root?.version ?? null };\n}\n\nexport function inspectMaintenanceSupportPayload(options: {\n table: DatasetMaintenanceSupportTable;\n payload: JsonObject;\n schemas?: DatasetMaintenanceSupportSchemas;\n}): {\n identity: { id: string | null; version: string | null };\n schemaResult: SafeParseResult;\n} {\n const schema = options.schemas?.[options.table] ?? DEFAULT_SUPPORT_SCHEMAS[options.table];\n return {\n identity: maintenancePayloadIdentity(options.payload),\n schemaResult: schema.safeParse(options.payload),\n };\n}\n"]}