@tiangong-lca/cli 0.0.7 → 0.0.8
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/README.md +83 -2
- package/dist/src/cli.js +1327 -40
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-author.js +100 -0
- package/dist/src/lib/dataset-author.js.map +1 -0
- package/dist/src/lib/dataset-bilingual.js +545 -0
- package/dist/src/lib/dataset-bilingual.js.map +1 -0
- package/dist/src/lib/dataset-contract.js +350 -0
- package/dist/src/lib/dataset-contract.js.map +1 -0
- package/dist/src/lib/dataset-evidence-search.js +636 -0
- package/dist/src/lib/dataset-evidence-search.js.map +1 -0
- package/dist/src/lib/dataset-import-lca.js +171 -0
- package/dist/src/lib/dataset-import-lca.js.map +1 -0
- package/dist/src/lib/dataset-remote-refresh.js +166 -0
- package/dist/src/lib/dataset-remote-refresh.js.map +1 -0
- package/dist/src/lib/dataset-remote-verify.js +543 -0
- package/dist/src/lib/dataset-remote-verify.js.map +1 -0
- package/dist/src/lib/dataset-validate.js +63 -7
- package/dist/src/lib/dataset-validate.js.map +1 -1
- package/dist/src/lib/flow-payload-validation.js +51 -0
- package/dist/src/lib/flow-payload-validation.js.map +1 -0
- package/dist/src/lib/flow-publish-reviewed-data.js +16 -0
- package/dist/src/lib/flow-publish-reviewed-data.js.map +1 -1
- package/dist/src/lib/flow-publish-version.js +182 -12
- package/dist/src/lib/flow-publish-version.js.map +1 -1
- package/dist/src/lib/identity-preflight.js +1021 -0
- package/dist/src/lib/identity-preflight.js.map +1 -0
- package/dist/src/lib/process-auto-build.js +147 -0
- package/dist/src/lib/process-auto-build.js.map +1 -1
- package/dist/src/lib/process-dedup-review.js +51 -0
- package/dist/src/lib/process-dedup-review.js.map +1 -1
- package/dist/src/lib/process-flow-build-plan.js +1071 -0
- package/dist/src/lib/process-flow-build-plan.js.map +1 -0
- package/dist/src/lib/process-payload-validation.js +14 -7
- package/dist/src/lib/process-payload-validation.js.map +1 -1
- package/dist/src/lib/process-publish-build.js +122 -4
- package/dist/src/lib/process-publish-build.js.map +1 -1
- package/dist/src/lib/process-refresh-references.js +19 -10
- package/dist/src/lib/process-refresh-references.js.map +1 -1
- package/dist/src/lib/process-required-fields.js +810 -0
- package/dist/src/lib/process-required-fields.js.map +1 -0
- package/dist/src/lib/process-save-draft-run.js +4 -1
- package/dist/src/lib/process-save-draft-run.js.map +1 -1
- package/dist/src/lib/publish.js +100 -0
- package/dist/src/lib/publish.js.map +1 -1
- package/dist/src/lib/review-flow.js +58 -0
- package/dist/src/lib/review-flow.js.map +1 -1
- package/dist/src/lib/review-process.js +150 -2
- package/dist/src/lib/review-process.js.map +1 -1
- package/dist/src/lib/runtime-rulesets.js +283 -0
- package/dist/src/lib/runtime-rulesets.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { writeJsonArtifact, writeJsonLinesArtifact } from './artifacts.js';
|
|
3
|
+
import { CliError } from './errors.js';
|
|
4
|
+
import { createSupabaseDataClient, requireSupabaseRestRuntime, runSupabaseArrayQuery, } from './supabase-client.js';
|
|
5
|
+
import { createSupabaseDataRuntime } from './supabase-session.js';
|
|
6
|
+
import { firstNonEmpty, isRecord, readDatasetRowsInput, trimToken, unwrapDatasetPayload, } from './dataset-local.js';
|
|
7
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
8
|
+
const ROOT_DATASET_DESCRIPTORS = [
|
|
9
|
+
{
|
|
10
|
+
wrapper: 'processDataSet',
|
|
11
|
+
table: 'processes',
|
|
12
|
+
type: 'process data set',
|
|
13
|
+
information_key: 'processInformation',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
wrapper: 'flowDataSet',
|
|
17
|
+
table: 'flows',
|
|
18
|
+
type: 'flow data set',
|
|
19
|
+
information_key: 'flowInformation',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
wrapper: 'lifeCycleModelDataSet',
|
|
23
|
+
table: 'lifecyclemodels',
|
|
24
|
+
type: 'life cycle model data set',
|
|
25
|
+
information_key: 'lifeCycleModelInformation',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
wrapper: 'sourceDataSet',
|
|
29
|
+
table: 'sources',
|
|
30
|
+
type: 'source data set',
|
|
31
|
+
information_key: 'sourceInformation',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
wrapper: 'contactDataSet',
|
|
35
|
+
table: 'contacts',
|
|
36
|
+
type: 'contact data set',
|
|
37
|
+
information_key: 'contactInformation',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
wrapper: 'flowPropertyDataSet',
|
|
41
|
+
table: 'flowproperties',
|
|
42
|
+
type: 'flow property data set',
|
|
43
|
+
information_key: 'flowPropertyInformation',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
wrapper: 'unitGroupDataSet',
|
|
47
|
+
table: 'unitgroups',
|
|
48
|
+
type: 'unit group data set',
|
|
49
|
+
information_key: 'unitGroupInformation',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
wrapper: 'LCIAMethodDataSet',
|
|
53
|
+
table: 'lciamethods',
|
|
54
|
+
type: 'LCIA method data set',
|
|
55
|
+
information_key: 'LCIAMethodInformation',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
const TABLE_ALIASES = new Map([
|
|
59
|
+
['contact', 'contacts'],
|
|
60
|
+
['contact data set', 'contacts'],
|
|
61
|
+
['contacts', 'contacts'],
|
|
62
|
+
['flow', 'flows'],
|
|
63
|
+
['flow data set', 'flows'],
|
|
64
|
+
['flows', 'flows'],
|
|
65
|
+
['flow property', 'flowproperties'],
|
|
66
|
+
['flow property data set', 'flowproperties'],
|
|
67
|
+
['flowproperties', 'flowproperties'],
|
|
68
|
+
['lcia method', 'lciamethods'],
|
|
69
|
+
['lcia method data set', 'lciamethods'],
|
|
70
|
+
['lciamethod', 'lciamethods'],
|
|
71
|
+
['lciamethods', 'lciamethods'],
|
|
72
|
+
['life cycle model', 'lifecyclemodels'],
|
|
73
|
+
['life cycle model data set', 'lifecyclemodels'],
|
|
74
|
+
['lifecycle model', 'lifecyclemodels'],
|
|
75
|
+
['lifecycle model data set', 'lifecyclemodels'],
|
|
76
|
+
['lifecyclemodel', 'lifecyclemodels'],
|
|
77
|
+
['lifecyclemodels', 'lifecyclemodels'],
|
|
78
|
+
['process', 'processes'],
|
|
79
|
+
['process data set', 'processes'],
|
|
80
|
+
['processes', 'processes'],
|
|
81
|
+
['source', 'sources'],
|
|
82
|
+
['source data set', 'sources'],
|
|
83
|
+
['sources', 'sources'],
|
|
84
|
+
['unit group', 'unitgroups'],
|
|
85
|
+
['unit group data set', 'unitgroups'],
|
|
86
|
+
['unitgroup', 'unitgroups'],
|
|
87
|
+
['unitgroups', 'unitgroups'],
|
|
88
|
+
]);
|
|
89
|
+
const PATH_TABLE_HINTS = [
|
|
90
|
+
[/referenceToFlowDataSet$/u, 'flows'],
|
|
91
|
+
[/referenceToProcess$/u, 'processes'],
|
|
92
|
+
[/referenceToResultingProcess$/u, 'processes'],
|
|
93
|
+
[/referenceToFlowPropertyDataSet$/u, 'flowproperties'],
|
|
94
|
+
[/referenceToReferenceUnitGroup$/u, 'unitgroups'],
|
|
95
|
+
[/referenceToLCIAMethodDataSet$/u, 'lciamethods'],
|
|
96
|
+
[/referenceToDataSource$/u, 'sources'],
|
|
97
|
+
[/referenceToExternalDocumentation$/u, 'sources'],
|
|
98
|
+
[/referenceToDataSetFormat$/u, 'sources'],
|
|
99
|
+
[/referenceToComplianceSystem$/u, 'sources'],
|
|
100
|
+
[/referenceToDataSetUseApproval$/u, 'sources'],
|
|
101
|
+
[/referenceToContact$/u, 'contacts'],
|
|
102
|
+
[/referenceToCommissioner$/u, 'contacts'],
|
|
103
|
+
[/referenceToPersonOrEntity/u, 'contacts'],
|
|
104
|
+
[/referenceToNameOfReviewerAndInstitution$/u, 'contacts'],
|
|
105
|
+
];
|
|
106
|
+
const EMPTY_STATUS_COUNTS = {
|
|
107
|
+
ok: 0,
|
|
108
|
+
lookup_failed: 0,
|
|
109
|
+
missing_dataset: 0,
|
|
110
|
+
missing_version: 0,
|
|
111
|
+
unsupported_type: 0,
|
|
112
|
+
version_missing: 0,
|
|
113
|
+
version_outdated: 0,
|
|
114
|
+
};
|
|
115
|
+
const EMPTY_TABLE_COUNTS = {
|
|
116
|
+
contacts: 0,
|
|
117
|
+
flowproperties: 0,
|
|
118
|
+
flows: 0,
|
|
119
|
+
lciamethods: 0,
|
|
120
|
+
lifecyclemodels: 0,
|
|
121
|
+
processes: 0,
|
|
122
|
+
sources: 0,
|
|
123
|
+
unitgroups: 0,
|
|
124
|
+
};
|
|
125
|
+
function requireNonEmpty(value, label, code) {
|
|
126
|
+
const normalized = value.trim();
|
|
127
|
+
if (!normalized) {
|
|
128
|
+
throw new CliError(`Missing required ${label} value.`, {
|
|
129
|
+
code,
|
|
130
|
+
exitCode: 2,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return normalized;
|
|
134
|
+
}
|
|
135
|
+
function nowIso(now = new Date()) {
|
|
136
|
+
return now.toISOString();
|
|
137
|
+
}
|
|
138
|
+
function textValue(value) {
|
|
139
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
140
|
+
return String(value);
|
|
141
|
+
}
|
|
142
|
+
return trimToken(value);
|
|
143
|
+
}
|
|
144
|
+
function normalizeTableToken(value) {
|
|
145
|
+
return value ? value.trim().replace(/\s+/gu, ' ').toLowerCase() : null;
|
|
146
|
+
}
|
|
147
|
+
function tableFromType(value) {
|
|
148
|
+
const normalized = normalizeTableToken(value);
|
|
149
|
+
return normalized ? (TABLE_ALIASES.get(normalized) ?? null) : null;
|
|
150
|
+
}
|
|
151
|
+
function tableFromPath(pathExpression) {
|
|
152
|
+
const pathEnd = pathExpression.split('/').filter(Boolean).at(-1) ?? '';
|
|
153
|
+
return PATH_TABLE_HINTS.find(([pattern]) => pattern.test(pathEnd))?.[1] ?? null;
|
|
154
|
+
}
|
|
155
|
+
function shortDescription(value) {
|
|
156
|
+
if (typeof value === 'string') {
|
|
157
|
+
return textValue(value);
|
|
158
|
+
}
|
|
159
|
+
if (Array.isArray(value)) {
|
|
160
|
+
for (const entry of value) {
|
|
161
|
+
const text = shortDescription(entry);
|
|
162
|
+
if (text) {
|
|
163
|
+
return text;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
if (isRecord(value)) {
|
|
169
|
+
return textValue(value['#text'] ?? value.text ?? value.value);
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
function pointerPath(basePath, segment) {
|
|
174
|
+
const encoded = String(segment).replace(/~/gu, '~0').replace(/\//gu, '~1');
|
|
175
|
+
return `${basePath}/${encoded}`;
|
|
176
|
+
}
|
|
177
|
+
function rootOf(payload) {
|
|
178
|
+
for (const descriptor of ROOT_DATASET_DESCRIPTORS) {
|
|
179
|
+
if (isRecord(payload[descriptor.wrapper])) {
|
|
180
|
+
return { descriptor, root: payload[descriptor.wrapper] };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
function rootIdentity(row, payload) {
|
|
186
|
+
const root = rootOf(payload);
|
|
187
|
+
if (!root) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const information = isRecord(root.root[root.descriptor.information_key])
|
|
191
|
+
? root.root[root.descriptor.information_key]
|
|
192
|
+
: {};
|
|
193
|
+
const dataSetInformation = isRecord(information.dataSetInformation)
|
|
194
|
+
? information.dataSetInformation
|
|
195
|
+
: {};
|
|
196
|
+
const administrativeInformation = isRecord(root.root.administrativeInformation)
|
|
197
|
+
? root.root.administrativeInformation
|
|
198
|
+
: {};
|
|
199
|
+
const publicationAndOwnership = isRecord(administrativeInformation.publicationAndOwnership)
|
|
200
|
+
? administrativeInformation.publicationAndOwnership
|
|
201
|
+
: {};
|
|
202
|
+
return {
|
|
203
|
+
row_index: -1,
|
|
204
|
+
role: 'root',
|
|
205
|
+
table: root.descriptor.table,
|
|
206
|
+
type: root.descriptor.type,
|
|
207
|
+
id: firstNonEmpty(row.id, row.uuid, dataSetInformation['common:UUID']),
|
|
208
|
+
version: firstNonEmpty(row.version, publicationAndOwnership['common:dataSetVersion']),
|
|
209
|
+
path: `/${root.descriptor.wrapper}`,
|
|
210
|
+
short_description: shortDescription(dataSetInformation.name ?? dataSetInformation.shortName),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function referenceFromRecord(rowIndex, value, pathExpression) {
|
|
214
|
+
const id = firstNonEmpty(value['@refObjectId'], value.refObjectId, value.id);
|
|
215
|
+
if (!id) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
const type = firstNonEmpty(value['@type'], value.type);
|
|
219
|
+
const table = tableFromType(type) ?? tableFromPath(pathExpression);
|
|
220
|
+
return {
|
|
221
|
+
row_index: rowIndex,
|
|
222
|
+
role: 'reference',
|
|
223
|
+
table,
|
|
224
|
+
type,
|
|
225
|
+
id,
|
|
226
|
+
version: firstNonEmpty(value['@version'], value.version),
|
|
227
|
+
path: pathExpression,
|
|
228
|
+
short_description: shortDescription(value['common:shortDescription']),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function flowReferenceFromRecord(rowIndex, value, pathExpression) {
|
|
232
|
+
const id = firstNonEmpty(value['@flowUUID']);
|
|
233
|
+
return id
|
|
234
|
+
? {
|
|
235
|
+
row_index: rowIndex,
|
|
236
|
+
role: 'reference',
|
|
237
|
+
table: 'flows',
|
|
238
|
+
type: 'flow data set',
|
|
239
|
+
id,
|
|
240
|
+
version: firstNonEmpty(value['@version'], value.version),
|
|
241
|
+
path: pointerPath(pathExpression, '@flowUUID'),
|
|
242
|
+
short_description: null,
|
|
243
|
+
}
|
|
244
|
+
: null;
|
|
245
|
+
}
|
|
246
|
+
function collectReferencesFromValue(rowIndex, value, pathExpression, references) {
|
|
247
|
+
if (Array.isArray(value)) {
|
|
248
|
+
value.forEach((entry, index) => collectReferencesFromValue(rowIndex, entry, pointerPath(pathExpression, index), references));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (!isRecord(value)) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const ref = referenceFromRecord(rowIndex, value, pathExpression);
|
|
255
|
+
if (ref) {
|
|
256
|
+
references.push(ref);
|
|
257
|
+
}
|
|
258
|
+
const flowRef = flowReferenceFromRecord(rowIndex, value, pathExpression);
|
|
259
|
+
if (flowRef) {
|
|
260
|
+
references.push(flowRef);
|
|
261
|
+
}
|
|
262
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
263
|
+
collectReferencesFromValue(rowIndex, nested, pointerPath(pathExpression, key), references);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function collectRemoteReferences(rows) {
|
|
267
|
+
const references = [];
|
|
268
|
+
rows.forEach((row, index) => {
|
|
269
|
+
const payload = unwrapDatasetPayload(row);
|
|
270
|
+
const root = rootIdentity(row, payload);
|
|
271
|
+
if (root) {
|
|
272
|
+
references.push({ ...root, row_index: index });
|
|
273
|
+
}
|
|
274
|
+
collectReferencesFromValue(index, payload, '', references);
|
|
275
|
+
});
|
|
276
|
+
return references;
|
|
277
|
+
}
|
|
278
|
+
function compareVersions(left, right) {
|
|
279
|
+
if (!left && !right) {
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
if (!left) {
|
|
283
|
+
return -1;
|
|
284
|
+
}
|
|
285
|
+
if (!right) {
|
|
286
|
+
return 1;
|
|
287
|
+
}
|
|
288
|
+
const leftParts = left.split(/[._-]/u);
|
|
289
|
+
const rightParts = right.split(/[._-]/u);
|
|
290
|
+
const length = Math.max(leftParts.length, rightParts.length);
|
|
291
|
+
for (let index = 0; index < length; index += 1) {
|
|
292
|
+
const leftPart = leftParts[index] ?? '0';
|
|
293
|
+
const rightPart = rightParts[index] ?? '0';
|
|
294
|
+
const leftNumber = Number(leftPart);
|
|
295
|
+
const rightNumber = Number(rightPart);
|
|
296
|
+
if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) {
|
|
297
|
+
if (leftNumber !== rightNumber) {
|
|
298
|
+
return leftNumber > rightNumber ? 1 : -1;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
const compared = leftPart.localeCompare(rightPart);
|
|
303
|
+
if (compared !== 0) {
|
|
304
|
+
return compared > 0 ? 1 : -1;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return 0;
|
|
309
|
+
}
|
|
310
|
+
function buildRemoteUrl(restBaseUrl, table, id, version) {
|
|
311
|
+
const url = new URL(`${restBaseUrl.replace(/\/+$/u, '')}/${table}`);
|
|
312
|
+
url.searchParams.set('id', `eq.${id}`);
|
|
313
|
+
if (version) {
|
|
314
|
+
url.searchParams.set('version', `eq.${version}`);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
url.searchParams.set('order', 'version.desc');
|
|
318
|
+
url.searchParams.set('limit', '1');
|
|
319
|
+
}
|
|
320
|
+
return url.toString();
|
|
321
|
+
}
|
|
322
|
+
function normalizeRows(value) {
|
|
323
|
+
return Array.isArray(value)
|
|
324
|
+
? value
|
|
325
|
+
.filter(isRecord)
|
|
326
|
+
.map((row) => ({
|
|
327
|
+
id: firstNonEmpty(row.id) ?? '',
|
|
328
|
+
version: firstNonEmpty(row.version),
|
|
329
|
+
}))
|
|
330
|
+
.filter((row) => Boolean(row.id))
|
|
331
|
+
: [];
|
|
332
|
+
}
|
|
333
|
+
async function lookupRemoteDataset(options) {
|
|
334
|
+
const { client, restBaseUrl } = createSupabaseDataClient(options.runtime, options.fetchImpl, options.timeoutMs);
|
|
335
|
+
const exactSourceUrl = options.request.version
|
|
336
|
+
? buildRemoteUrl(restBaseUrl, options.request.table, options.request.id, options.request.version)
|
|
337
|
+
: null;
|
|
338
|
+
const latestSourceUrl = buildRemoteUrl(restBaseUrl, options.request.table, options.request.id, null);
|
|
339
|
+
const exactRows = options.request.version
|
|
340
|
+
? normalizeRows(await runSupabaseArrayQuery(client
|
|
341
|
+
.from(options.request.table)
|
|
342
|
+
.select('id,version')
|
|
343
|
+
.eq('id', options.request.id)
|
|
344
|
+
.eq('version', options.request.version), exactSourceUrl))
|
|
345
|
+
: [];
|
|
346
|
+
const latestRows = normalizeRows(await runSupabaseArrayQuery(client
|
|
347
|
+
.from(options.request.table)
|
|
348
|
+
.select('id,version')
|
|
349
|
+
.eq('id', options.request.id)
|
|
350
|
+
.order('version', { ascending: false })
|
|
351
|
+
.limit(1), latestSourceUrl));
|
|
352
|
+
return {
|
|
353
|
+
exact: exactRows[0] ?? null,
|
|
354
|
+
latest: latestRows[0] ?? null,
|
|
355
|
+
exact_source_url: exactSourceUrl,
|
|
356
|
+
latest_source_url: latestSourceUrl,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function checkMessage(reference, status) {
|
|
360
|
+
const label = `${reference.table ?? reference.type ?? 'unknown'}:${reference.id ?? '-'}@${reference.version ?? '-'}`;
|
|
361
|
+
switch (status) {
|
|
362
|
+
case 'ok':
|
|
363
|
+
return `Remote dataset reference is resolvable: ${label}.`;
|
|
364
|
+
case 'lookup_failed':
|
|
365
|
+
return `Remote lookup failed for dataset reference: ${label}.`;
|
|
366
|
+
case 'missing_dataset':
|
|
367
|
+
return `Remote dataset id does not exist: ${label}.`;
|
|
368
|
+
case 'missing_version':
|
|
369
|
+
return `Remote dataset id exists, but the requested version does not exist: ${label}.`;
|
|
370
|
+
case 'unsupported_type':
|
|
371
|
+
return `Dataset reference type cannot be mapped to a TianGong table: ${label}.`;
|
|
372
|
+
case 'version_missing':
|
|
373
|
+
return `Dataset reference is missing @version and cannot pass publish-readiness verification: ${label}.`;
|
|
374
|
+
case 'version_outdated':
|
|
375
|
+
return `Requested dataset version is lower than the latest published version: ${label}.`;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function classifyCheck(reference, lookup, lookupFailed, rootPolicy) {
|
|
379
|
+
let status = 'ok';
|
|
380
|
+
if (!reference.table || !reference.id) {
|
|
381
|
+
status = 'unsupported_type';
|
|
382
|
+
}
|
|
383
|
+
else if (lookupFailed) {
|
|
384
|
+
status = 'lookup_failed';
|
|
385
|
+
}
|
|
386
|
+
else if (!reference.version) {
|
|
387
|
+
status = 'version_missing';
|
|
388
|
+
}
|
|
389
|
+
else if (reference.role === 'root' && rootPolicy === 'candidate') {
|
|
390
|
+
if (!lookup?.latest) {
|
|
391
|
+
status = 'ok';
|
|
392
|
+
}
|
|
393
|
+
else if (!lookup.exact) {
|
|
394
|
+
status =
|
|
395
|
+
compareVersions(reference.version, lookup.latest.version) > 0
|
|
396
|
+
? 'ok'
|
|
397
|
+
: compareVersions(lookup.latest.version, reference.version) > 0
|
|
398
|
+
? 'version_outdated'
|
|
399
|
+
: 'missing_version';
|
|
400
|
+
}
|
|
401
|
+
else if (compareVersions(lookup.latest.version, reference.version) > 0) {
|
|
402
|
+
status = 'version_outdated';
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
else if (!lookup?.latest) {
|
|
406
|
+
status = 'missing_dataset';
|
|
407
|
+
}
|
|
408
|
+
else if (!lookup.exact) {
|
|
409
|
+
status = 'missing_version';
|
|
410
|
+
}
|
|
411
|
+
else if (compareVersions(lookup.latest.version, reference.version) > 0) {
|
|
412
|
+
status = 'version_outdated';
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
...reference,
|
|
416
|
+
status,
|
|
417
|
+
latest_version: lookup?.latest?.version ?? null,
|
|
418
|
+
exact_source_url: lookup?.exact_source_url ?? null,
|
|
419
|
+
latest_source_url: lookup?.latest_source_url ?? null,
|
|
420
|
+
message: checkMessage(reference, status),
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function blockerFromCheck(check) {
|
|
424
|
+
return check.status === 'ok'
|
|
425
|
+
? null
|
|
426
|
+
: {
|
|
427
|
+
code: check.status,
|
|
428
|
+
severity: 'error',
|
|
429
|
+
message: check.message,
|
|
430
|
+
row_index: check.row_index,
|
|
431
|
+
role: check.role,
|
|
432
|
+
table: check.table,
|
|
433
|
+
id: check.id,
|
|
434
|
+
version: check.version,
|
|
435
|
+
latest_version: check.latest_version,
|
|
436
|
+
path: check.path,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function buildFiles(outDir) {
|
|
440
|
+
const resolved = path.resolve(outDir);
|
|
441
|
+
return {
|
|
442
|
+
report: path.join(resolved, 'outputs', 'remote-verification-report.json'),
|
|
443
|
+
checks: path.join(resolved, 'outputs', 'remote-verification.jsonl'),
|
|
444
|
+
blockers: path.join(resolved, 'outputs', 'blockers.jsonl'),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function uniqueLookupKey(reference) {
|
|
448
|
+
return reference.table && reference.id
|
|
449
|
+
? `${reference.table}:${reference.id}:${reference.version ?? ''}`
|
|
450
|
+
: null;
|
|
451
|
+
}
|
|
452
|
+
export async function runDatasetRemoteVerify(options) {
|
|
453
|
+
const inputPath = path.resolve(requireNonEmpty(options.inputPath, '--input', 'DATASET_REMOTE_VERIFY_INPUT_REQUIRED'));
|
|
454
|
+
const outDir = path.resolve(requireNonEmpty(options.outDir, '--out-dir', 'DATASET_REMOTE_VERIFY_OUT_DIR_REQUIRED'));
|
|
455
|
+
const rows = readDatasetRowsInput(inputPath, options.rawInput);
|
|
456
|
+
const references = collectRemoteReferences(rows);
|
|
457
|
+
const rootPolicy = options.rootPolicy ?? 'existing';
|
|
458
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
459
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
460
|
+
const runtime = options.lookupDatasetImpl === undefined
|
|
461
|
+
? createSupabaseDataRuntime({
|
|
462
|
+
runtime: requireSupabaseRestRuntime(options.env ?? process.env),
|
|
463
|
+
fetchImpl,
|
|
464
|
+
timeoutMs,
|
|
465
|
+
now: options.now,
|
|
466
|
+
})
|
|
467
|
+
: null;
|
|
468
|
+
const lookupImpl = options.lookupDatasetImpl ??
|
|
469
|
+
((request) => lookupRemoteDataset({
|
|
470
|
+
runtime: runtime,
|
|
471
|
+
fetchImpl,
|
|
472
|
+
timeoutMs,
|
|
473
|
+
request,
|
|
474
|
+
}));
|
|
475
|
+
const lookupCache = new Map();
|
|
476
|
+
const checks = [];
|
|
477
|
+
for (const reference of references) {
|
|
478
|
+
let lookup = null;
|
|
479
|
+
let lookupFailed = false;
|
|
480
|
+
const lookupKey = uniqueLookupKey(reference);
|
|
481
|
+
if (reference.table && reference.id && lookupKey) {
|
|
482
|
+
try {
|
|
483
|
+
if (!lookupCache.has(lookupKey)) {
|
|
484
|
+
lookupCache.set(lookupKey, lookupImpl({
|
|
485
|
+
table: reference.table,
|
|
486
|
+
id: reference.id,
|
|
487
|
+
version: reference.version,
|
|
488
|
+
}));
|
|
489
|
+
}
|
|
490
|
+
lookup = await lookupCache.get(lookupKey);
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
lookupFailed = true;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
checks.push(classifyCheck(reference, lookup, lookupFailed, rootPolicy));
|
|
497
|
+
}
|
|
498
|
+
const blockers = checks
|
|
499
|
+
.map(blockerFromCheck)
|
|
500
|
+
.filter((blocker) => blocker !== null);
|
|
501
|
+
const byStatus = { ...EMPTY_STATUS_COUNTS };
|
|
502
|
+
const byTable = { ...EMPTY_TABLE_COUNTS };
|
|
503
|
+
checks.forEach((check) => {
|
|
504
|
+
byStatus[check.status] += 1;
|
|
505
|
+
if (check.table) {
|
|
506
|
+
byTable[check.table] += 1;
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
const files = buildFiles(outDir);
|
|
510
|
+
const report = {
|
|
511
|
+
schema_version: 1,
|
|
512
|
+
generated_at_utc: nowIso(options.now),
|
|
513
|
+
status: blockers.length > 0 ? 'blocked_remote_verification' : 'passed_remote_verification',
|
|
514
|
+
root_policy: rootPolicy,
|
|
515
|
+
input_path: inputPath,
|
|
516
|
+
out_dir: outDir,
|
|
517
|
+
counts: {
|
|
518
|
+
rows: rows.length,
|
|
519
|
+
references: references.length,
|
|
520
|
+
checked: checks.length,
|
|
521
|
+
blockers: blockers.length,
|
|
522
|
+
by_status: byStatus,
|
|
523
|
+
by_table: byTable,
|
|
524
|
+
},
|
|
525
|
+
blockers,
|
|
526
|
+
files,
|
|
527
|
+
};
|
|
528
|
+
writeJsonArtifact(files.report, report);
|
|
529
|
+
writeJsonLinesArtifact(files.checks, checks);
|
|
530
|
+
writeJsonLinesArtifact(files.blockers, blockers);
|
|
531
|
+
return report;
|
|
532
|
+
}
|
|
533
|
+
export const __testInternals = {
|
|
534
|
+
buildRemoteUrl,
|
|
535
|
+
collectRemoteReferences,
|
|
536
|
+
compareVersions,
|
|
537
|
+
lookupRemoteDataset,
|
|
538
|
+
normalizeRows,
|
|
539
|
+
shortDescription,
|
|
540
|
+
tableFromPath,
|
|
541
|
+
tableFromType,
|
|
542
|
+
};
|
|
543
|
+
//# sourceMappingURL=dataset-remote-verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset-remote-verify.js","sourceRoot":"","sources":["../../../src/lib/dataset-remote-verify.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\nimport { writeJsonArtifact, writeJsonLinesArtifact } from './artifacts.js';\nimport { CliError } from './errors.js';\nimport type { FetchLike } from './http.js';\nimport {\n createSupabaseDataClient,\n requireSupabaseRestRuntime,\n runSupabaseArrayQuery,\n type SupabaseDataRuntime,\n} from './supabase-client.js';\nimport { createSupabaseDataRuntime } from './supabase-session.js';\nimport {\n firstNonEmpty,\n isRecord,\n readDatasetRowsInput,\n trimToken,\n unwrapDatasetPayload,\n type JsonObject,\n} from './dataset-local.js';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport type RemoteDatasetTable =\n | 'contacts'\n | 'flowproperties'\n | 'flows'\n | 'lciamethods'\n | 'lifecyclemodels'\n | 'processes'\n | 'sources'\n | 'unitgroups';\n\nexport type RemoteVerificationReferenceRole = 'root' | 'reference';\nexport type RemoteVerificationRootPolicy = 'existing' | 'candidate';\n\nexport type RemoteVerificationStatus =\n | 'ok'\n | 'lookup_failed'\n | 'missing_dataset'\n | 'missing_version'\n | 'unsupported_type'\n | 'version_missing'\n | 'version_outdated';\n\nexport type RemoteDatasetReference = {\n row_index: number;\n role: RemoteVerificationReferenceRole;\n table: RemoteDatasetTable | null;\n type: string | null;\n id: string | null;\n version: string | null;\n path: string;\n short_description: string | null;\n};\n\nexport type RemoteDatasetLookupRow = {\n id: string;\n version: string | null;\n};\n\nexport type RemoteDatasetLookup = {\n exact: RemoteDatasetLookupRow | null;\n latest: RemoteDatasetLookupRow | null;\n exact_source_url: string | null;\n latest_source_url: string | null;\n};\n\nexport type RemoteDatasetLookupRequest = {\n table: RemoteDatasetTable;\n id: string;\n version: string | null;\n};\n\nexport type RemoteVerificationCheck = {\n row_index: number;\n role: RemoteVerificationReferenceRole;\n table: RemoteDatasetTable | null;\n type: string | null;\n id: string | null;\n version: string | null;\n path: string;\n short_description: string | null;\n status: RemoteVerificationStatus;\n latest_version: string | null;\n exact_source_url: string | null;\n latest_source_url: string | null;\n message: string;\n};\n\nexport type RemoteVerificationBlocker = {\n code: RemoteVerificationStatus;\n severity: 'error';\n message: string;\n row_index: number;\n role: RemoteVerificationReferenceRole;\n table: RemoteDatasetTable | null;\n id: string | null;\n version: string | null;\n latest_version: string | null;\n path: string;\n};\n\nexport type DatasetRemoteVerificationReport = {\n schema_version: 1;\n generated_at_utc: string;\n status: 'passed_remote_verification' | 'blocked_remote_verification';\n root_policy: RemoteVerificationRootPolicy;\n input_path: string;\n out_dir: string;\n counts: {\n rows: number;\n references: number;\n checked: number;\n blockers: number;\n by_status: Record<RemoteVerificationStatus, number>;\n by_table: Record<RemoteDatasetTable, number>;\n };\n blockers: RemoteVerificationBlocker[];\n files: {\n report: string;\n checks: string;\n blockers: string;\n };\n};\n\nexport type RunDatasetRemoteVerifyOptions = {\n inputPath: string;\n outDir: string;\n rootPolicy?: RemoteVerificationRootPolicy;\n rawInput?: unknown;\n env?: NodeJS.ProcessEnv;\n fetchImpl?: FetchLike;\n timeoutMs?: number;\n now?: Date;\n lookupDatasetImpl?: (request: RemoteDatasetLookupRequest) => Promise<RemoteDatasetLookup>;\n};\n\ntype RootDatasetDescriptor = {\n wrapper: string;\n table: RemoteDatasetTable;\n type: string;\n information_key: string;\n};\n\nconst ROOT_DATASET_DESCRIPTORS: RootDatasetDescriptor[] = [\n {\n wrapper: 'processDataSet',\n table: 'processes',\n type: 'process data set',\n information_key: 'processInformation',\n },\n {\n wrapper: 'flowDataSet',\n table: 'flows',\n type: 'flow data set',\n information_key: 'flowInformation',\n },\n {\n wrapper: 'lifeCycleModelDataSet',\n table: 'lifecyclemodels',\n type: 'life cycle model data set',\n information_key: 'lifeCycleModelInformation',\n },\n {\n wrapper: 'sourceDataSet',\n table: 'sources',\n type: 'source data set',\n information_key: 'sourceInformation',\n },\n {\n wrapper: 'contactDataSet',\n table: 'contacts',\n type: 'contact data set',\n information_key: 'contactInformation',\n },\n {\n wrapper: 'flowPropertyDataSet',\n table: 'flowproperties',\n type: 'flow property data set',\n information_key: 'flowPropertyInformation',\n },\n {\n wrapper: 'unitGroupDataSet',\n table: 'unitgroups',\n type: 'unit group data set',\n information_key: 'unitGroupInformation',\n },\n {\n wrapper: 'LCIAMethodDataSet',\n table: 'lciamethods',\n type: 'LCIA method data set',\n information_key: 'LCIAMethodInformation',\n },\n];\n\nconst TABLE_ALIASES = new Map<string, RemoteDatasetTable>([\n ['contact', 'contacts'],\n ['contact data set', 'contacts'],\n ['contacts', 'contacts'],\n ['flow', 'flows'],\n ['flow data set', 'flows'],\n ['flows', 'flows'],\n ['flow property', 'flowproperties'],\n ['flow property data set', 'flowproperties'],\n ['flowproperties', 'flowproperties'],\n ['lcia method', 'lciamethods'],\n ['lcia method data set', 'lciamethods'],\n ['lciamethod', 'lciamethods'],\n ['lciamethods', 'lciamethods'],\n ['life cycle model', 'lifecyclemodels'],\n ['life cycle model data set', 'lifecyclemodels'],\n ['lifecycle model', 'lifecyclemodels'],\n ['lifecycle model data set', 'lifecyclemodels'],\n ['lifecyclemodel', 'lifecyclemodels'],\n ['lifecyclemodels', 'lifecyclemodels'],\n ['process', 'processes'],\n ['process data set', 'processes'],\n ['processes', 'processes'],\n ['source', 'sources'],\n ['source data set', 'sources'],\n ['sources', 'sources'],\n ['unit group', 'unitgroups'],\n ['unit group data set', 'unitgroups'],\n ['unitgroup', 'unitgroups'],\n ['unitgroups', 'unitgroups'],\n]);\n\nconst PATH_TABLE_HINTS: Array<[RegExp, RemoteDatasetTable]> = [\n [/referenceToFlowDataSet$/u, 'flows'],\n [/referenceToProcess$/u, 'processes'],\n [/referenceToResultingProcess$/u, 'processes'],\n [/referenceToFlowPropertyDataSet$/u, 'flowproperties'],\n [/referenceToReferenceUnitGroup$/u, 'unitgroups'],\n [/referenceToLCIAMethodDataSet$/u, 'lciamethods'],\n [/referenceToDataSource$/u, 'sources'],\n [/referenceToExternalDocumentation$/u, 'sources'],\n [/referenceToDataSetFormat$/u, 'sources'],\n [/referenceToComplianceSystem$/u, 'sources'],\n [/referenceToDataSetUseApproval$/u, 'sources'],\n [/referenceToContact$/u, 'contacts'],\n [/referenceToCommissioner$/u, 'contacts'],\n [/referenceToPersonOrEntity/u, 'contacts'],\n [/referenceToNameOfReviewerAndInstitution$/u, 'contacts'],\n];\n\nconst EMPTY_STATUS_COUNTS: Record<RemoteVerificationStatus, number> = {\n ok: 0,\n lookup_failed: 0,\n missing_dataset: 0,\n missing_version: 0,\n unsupported_type: 0,\n version_missing: 0,\n version_outdated: 0,\n};\n\nconst EMPTY_TABLE_COUNTS: Record<RemoteDatasetTable, number> = {\n contacts: 0,\n flowproperties: 0,\n flows: 0,\n lciamethods: 0,\n lifecyclemodels: 0,\n processes: 0,\n sources: 0,\n unitgroups: 0,\n};\n\nfunction requireNonEmpty(value: string, label: string, code: string): string {\n const normalized = value.trim();\n if (!normalized) {\n throw new CliError(`Missing required ${label} value.`, {\n code,\n exitCode: 2,\n });\n }\n return normalized;\n}\n\nfunction nowIso(now: Date = new Date()): string {\n return now.toISOString();\n}\n\nfunction textValue(value: unknown): string | null {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return String(value);\n }\n return trimToken(value);\n}\n\nfunction normalizeTableToken(value: string | null): string | null {\n return value ? value.trim().replace(/\\s+/gu, ' ').toLowerCase() : null;\n}\n\nfunction tableFromType(value: string | null): RemoteDatasetTable | null {\n const normalized = normalizeTableToken(value);\n return normalized ? (TABLE_ALIASES.get(normalized) ?? null) : null;\n}\n\nfunction tableFromPath(pathExpression: string): RemoteDatasetTable | null {\n const pathEnd = pathExpression.split('/').filter(Boolean).at(-1) ?? '';\n return PATH_TABLE_HINTS.find(([pattern]) => pattern.test(pathEnd))?.[1] ?? null;\n}\n\nfunction shortDescription(value: unknown): string | null {\n if (typeof value === 'string') {\n return textValue(value);\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n const text = shortDescription(entry);\n if (text) {\n return text;\n }\n }\n return null;\n }\n if (isRecord(value)) {\n return textValue(value['#text'] ?? value.text ?? value.value);\n }\n return null;\n}\n\nfunction pointerPath(basePath: string, segment: string | number): string {\n const encoded = String(segment).replace(/~/gu, '~0').replace(/\\//gu, '~1');\n return `${basePath}/${encoded}`;\n}\n\nfunction rootOf(\n payload: JsonObject,\n): { descriptor: RootDatasetDescriptor; root: JsonObject } | null {\n for (const descriptor of ROOT_DATASET_DESCRIPTORS) {\n if (isRecord(payload[descriptor.wrapper])) {\n return { descriptor, root: payload[descriptor.wrapper] as JsonObject };\n }\n }\n return null;\n}\n\nfunction rootIdentity(row: JsonObject, payload: JsonObject): RemoteDatasetReference | null {\n const root = rootOf(payload);\n if (!root) {\n return null;\n }\n const information = isRecord(root.root[root.descriptor.information_key])\n ? (root.root[root.descriptor.information_key] as JsonObject)\n : {};\n const dataSetInformation = isRecord(information.dataSetInformation)\n ? information.dataSetInformation\n : {};\n const administrativeInformation = isRecord(root.root.administrativeInformation)\n ? root.root.administrativeInformation\n : {};\n const publicationAndOwnership = isRecord(administrativeInformation.publicationAndOwnership)\n ? administrativeInformation.publicationAndOwnership\n : {};\n\n return {\n row_index: -1,\n role: 'root',\n table: root.descriptor.table,\n type: root.descriptor.type,\n id: firstNonEmpty(row.id, row.uuid, dataSetInformation['common:UUID']),\n version: firstNonEmpty(row.version, publicationAndOwnership['common:dataSetVersion']),\n path: `/${root.descriptor.wrapper}`,\n short_description: shortDescription(dataSetInformation.name ?? dataSetInformation.shortName),\n };\n}\n\nfunction referenceFromRecord(\n rowIndex: number,\n value: JsonObject,\n pathExpression: string,\n): RemoteDatasetReference | null {\n const id = firstNonEmpty(value['@refObjectId'], value.refObjectId, value.id);\n if (!id) {\n return null;\n }\n const type = firstNonEmpty(value['@type'], value.type);\n const table = tableFromType(type) ?? tableFromPath(pathExpression);\n return {\n row_index: rowIndex,\n role: 'reference',\n table,\n type,\n id,\n version: firstNonEmpty(value['@version'], value.version),\n path: pathExpression,\n short_description: shortDescription(value['common:shortDescription']),\n };\n}\n\nfunction flowReferenceFromRecord(\n rowIndex: number,\n value: JsonObject,\n pathExpression: string,\n): RemoteDatasetReference | null {\n const id = firstNonEmpty(value['@flowUUID']);\n return id\n ? {\n row_index: rowIndex,\n role: 'reference',\n table: 'flows',\n type: 'flow data set',\n id,\n version: firstNonEmpty(value['@version'], value.version),\n path: pointerPath(pathExpression, '@flowUUID'),\n short_description: null,\n }\n : null;\n}\n\nfunction collectReferencesFromValue(\n rowIndex: number,\n value: unknown,\n pathExpression: string,\n references: RemoteDatasetReference[],\n): void {\n if (Array.isArray(value)) {\n value.forEach((entry, index) =>\n collectReferencesFromValue(rowIndex, entry, pointerPath(pathExpression, index), references),\n );\n return;\n }\n\n if (!isRecord(value)) {\n return;\n }\n\n const ref = referenceFromRecord(rowIndex, value, pathExpression);\n if (ref) {\n references.push(ref);\n }\n const flowRef = flowReferenceFromRecord(rowIndex, value, pathExpression);\n if (flowRef) {\n references.push(flowRef);\n }\n for (const [key, nested] of Object.entries(value)) {\n collectReferencesFromValue(rowIndex, nested, pointerPath(pathExpression, key), references);\n }\n}\n\nfunction collectRemoteReferences(rows: JsonObject[]): RemoteDatasetReference[] {\n const references: RemoteDatasetReference[] = [];\n rows.forEach((row, index) => {\n const payload = unwrapDatasetPayload(row);\n const root = rootIdentity(row, payload);\n if (root) {\n references.push({ ...root, row_index: index });\n }\n collectReferencesFromValue(index, payload, '', references);\n });\n return references;\n}\n\nfunction compareVersions(left: string | null, right: string | null): number {\n if (!left && !right) {\n return 0;\n }\n if (!left) {\n return -1;\n }\n if (!right) {\n return 1;\n }\n const leftParts = left.split(/[._-]/u);\n const rightParts = right.split(/[._-]/u);\n const length = Math.max(leftParts.length, rightParts.length);\n for (let index = 0; index < length; index += 1) {\n const leftPart = leftParts[index] ?? '0';\n const rightPart = rightParts[index] ?? '0';\n const leftNumber = Number(leftPart);\n const rightNumber = Number(rightPart);\n if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) {\n if (leftNumber !== rightNumber) {\n return leftNumber > rightNumber ? 1 : -1;\n }\n } else {\n const compared = leftPart.localeCompare(rightPart);\n if (compared !== 0) {\n return compared > 0 ? 1 : -1;\n }\n }\n }\n return 0;\n}\n\nfunction buildRemoteUrl(\n restBaseUrl: string,\n table: RemoteDatasetTable,\n id: string,\n version: string | null,\n): string {\n const url = new URL(`${restBaseUrl.replace(/\\/+$/u, '')}/${table}`);\n url.searchParams.set('id', `eq.${id}`);\n if (version) {\n url.searchParams.set('version', `eq.${version}`);\n } else {\n url.searchParams.set('order', 'version.desc');\n url.searchParams.set('limit', '1');\n }\n return url.toString();\n}\n\nfunction normalizeRows(value: unknown): RemoteDatasetLookupRow[] {\n return Array.isArray(value)\n ? value\n .filter(isRecord)\n .map((row) => ({\n id: firstNonEmpty(row.id) ?? '',\n version: firstNonEmpty(row.version),\n }))\n .filter((row) => Boolean(row.id))\n : [];\n}\n\nasync function lookupRemoteDataset(options: {\n runtime: SupabaseDataRuntime;\n fetchImpl: FetchLike;\n timeoutMs: number;\n request: RemoteDatasetLookupRequest;\n}): Promise<RemoteDatasetLookup> {\n const { client, restBaseUrl } = createSupabaseDataClient(\n options.runtime,\n options.fetchImpl,\n options.timeoutMs,\n );\n const exactSourceUrl = options.request.version\n ? buildRemoteUrl(\n restBaseUrl,\n options.request.table,\n options.request.id,\n options.request.version,\n )\n : null;\n const latestSourceUrl = buildRemoteUrl(\n restBaseUrl,\n options.request.table,\n options.request.id,\n null,\n );\n const exactRows = options.request.version\n ? normalizeRows(\n await runSupabaseArrayQuery(\n client\n .from(options.request.table)\n .select('id,version')\n .eq('id', options.request.id)\n .eq('version', options.request.version),\n exactSourceUrl as string,\n ),\n )\n : [];\n const latestRows = normalizeRows(\n await runSupabaseArrayQuery(\n client\n .from(options.request.table)\n .select('id,version')\n .eq('id', options.request.id)\n .order('version', { ascending: false })\n .limit(1),\n latestSourceUrl,\n ),\n );\n return {\n exact: exactRows[0] ?? null,\n latest: latestRows[0] ?? null,\n exact_source_url: exactSourceUrl,\n latest_source_url: latestSourceUrl,\n };\n}\n\nfunction checkMessage(reference: RemoteDatasetReference, status: RemoteVerificationStatus): string {\n const label = `${reference.table ?? reference.type ?? 'unknown'}:${reference.id ?? '-'}@${\n reference.version ?? '-'\n }`;\n switch (status) {\n case 'ok':\n return `Remote dataset reference is resolvable: ${label}.`;\n case 'lookup_failed':\n return `Remote lookup failed for dataset reference: ${label}.`;\n case 'missing_dataset':\n return `Remote dataset id does not exist: ${label}.`;\n case 'missing_version':\n return `Remote dataset id exists, but the requested version does not exist: ${label}.`;\n case 'unsupported_type':\n return `Dataset reference type cannot be mapped to a TianGong table: ${label}.`;\n case 'version_missing':\n return `Dataset reference is missing @version and cannot pass publish-readiness verification: ${label}.`;\n case 'version_outdated':\n return `Requested dataset version is lower than the latest published version: ${label}.`;\n }\n}\n\nfunction classifyCheck(\n reference: RemoteDatasetReference,\n lookup: RemoteDatasetLookup | null,\n lookupFailed: boolean,\n rootPolicy: RemoteVerificationRootPolicy,\n): RemoteVerificationCheck {\n let status: RemoteVerificationStatus = 'ok';\n if (!reference.table || !reference.id) {\n status = 'unsupported_type';\n } else if (lookupFailed) {\n status = 'lookup_failed';\n } else if (!reference.version) {\n status = 'version_missing';\n } else if (reference.role === 'root' && rootPolicy === 'candidate') {\n if (!lookup?.latest) {\n status = 'ok';\n } else if (!lookup.exact) {\n status =\n compareVersions(reference.version, lookup.latest.version) > 0\n ? 'ok'\n : compareVersions(lookup.latest.version, reference.version) > 0\n ? 'version_outdated'\n : 'missing_version';\n } else if (compareVersions(lookup.latest.version, reference.version) > 0) {\n status = 'version_outdated';\n }\n } else if (!lookup?.latest) {\n status = 'missing_dataset';\n } else if (!lookup.exact) {\n status = 'missing_version';\n } else if (compareVersions(lookup.latest.version, reference.version) > 0) {\n status = 'version_outdated';\n }\n return {\n ...reference,\n status,\n latest_version: lookup?.latest?.version ?? null,\n exact_source_url: lookup?.exact_source_url ?? null,\n latest_source_url: lookup?.latest_source_url ?? null,\n message: checkMessage(reference, status),\n };\n}\n\nfunction blockerFromCheck(check: RemoteVerificationCheck): RemoteVerificationBlocker | null {\n return check.status === 'ok'\n ? null\n : {\n code: check.status,\n severity: 'error',\n message: check.message,\n row_index: check.row_index,\n role: check.role,\n table: check.table,\n id: check.id,\n version: check.version,\n latest_version: check.latest_version,\n path: check.path,\n };\n}\n\nfunction buildFiles(outDir: string): DatasetRemoteVerificationReport['files'] {\n const resolved = path.resolve(outDir);\n return {\n report: path.join(resolved, 'outputs', 'remote-verification-report.json'),\n checks: path.join(resolved, 'outputs', 'remote-verification.jsonl'),\n blockers: path.join(resolved, 'outputs', 'blockers.jsonl'),\n };\n}\n\nfunction uniqueLookupKey(reference: RemoteDatasetReference): string | null {\n return reference.table && reference.id\n ? `${reference.table}:${reference.id}:${reference.version ?? ''}`\n : null;\n}\n\nexport async function runDatasetRemoteVerify(\n options: RunDatasetRemoteVerifyOptions,\n): Promise<DatasetRemoteVerificationReport> {\n const inputPath = path.resolve(\n requireNonEmpty(options.inputPath, '--input', 'DATASET_REMOTE_VERIFY_INPUT_REQUIRED'),\n );\n const outDir = path.resolve(\n requireNonEmpty(options.outDir, '--out-dir', 'DATASET_REMOTE_VERIFY_OUT_DIR_REQUIRED'),\n );\n const rows = readDatasetRowsInput(inputPath, options.rawInput);\n const references = collectRemoteReferences(rows);\n const rootPolicy = options.rootPolicy ?? 'existing';\n const fetchImpl = options.fetchImpl ?? (fetch as FetchLike);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const runtime =\n options.lookupDatasetImpl === undefined\n ? createSupabaseDataRuntime({\n runtime: requireSupabaseRestRuntime(options.env ?? process.env),\n fetchImpl,\n timeoutMs,\n now: options.now,\n })\n : null;\n const lookupImpl =\n options.lookupDatasetImpl ??\n ((request: RemoteDatasetLookupRequest) =>\n lookupRemoteDataset({\n runtime: runtime as SupabaseDataRuntime,\n fetchImpl,\n timeoutMs,\n request,\n }));\n const lookupCache = new Map<string, Promise<RemoteDatasetLookup>>();\n const checks: RemoteVerificationCheck[] = [];\n\n for (const reference of references) {\n let lookup: RemoteDatasetLookup | null = null;\n let lookupFailed = false;\n const lookupKey = uniqueLookupKey(reference);\n if (reference.table && reference.id && lookupKey) {\n try {\n if (!lookupCache.has(lookupKey)) {\n lookupCache.set(\n lookupKey,\n lookupImpl({\n table: reference.table,\n id: reference.id,\n version: reference.version,\n }),\n );\n }\n lookup = await lookupCache.get(lookupKey)!;\n } catch {\n lookupFailed = true;\n }\n }\n checks.push(classifyCheck(reference, lookup, lookupFailed, rootPolicy));\n }\n\n const blockers = checks\n .map(blockerFromCheck)\n .filter((blocker): blocker is RemoteVerificationBlocker => blocker !== null);\n const byStatus = { ...EMPTY_STATUS_COUNTS };\n const byTable = { ...EMPTY_TABLE_COUNTS };\n checks.forEach((check) => {\n byStatus[check.status] += 1;\n if (check.table) {\n byTable[check.table] += 1;\n }\n });\n\n const files = buildFiles(outDir);\n const report: DatasetRemoteVerificationReport = {\n schema_version: 1,\n generated_at_utc: nowIso(options.now),\n status: blockers.length > 0 ? 'blocked_remote_verification' : 'passed_remote_verification',\n root_policy: rootPolicy,\n input_path: inputPath,\n out_dir: outDir,\n counts: {\n rows: rows.length,\n references: references.length,\n checked: checks.length,\n blockers: blockers.length,\n by_status: byStatus,\n by_table: byTable,\n },\n blockers,\n files,\n };\n\n writeJsonArtifact(files.report, report);\n writeJsonLinesArtifact(files.checks, checks);\n writeJsonLinesArtifact(files.blockers, blockers);\n\n return report;\n}\n\nexport const __testInternals = {\n buildRemoteUrl,\n collectRemoteReferences,\n compareVersions,\n lookupRemoteDataset,\n normalizeRows,\n shortDescription,\n tableFromPath,\n tableFromType,\n};\n"]}
|