@butinapp/shapes 0.1.0 → 0.1.1
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/export-bundle.d.ts +1 -0
- package/dist/export-bundle.js +54 -4
- package/package.json +2 -2
package/dist/export-bundle.d.ts
CHANGED
package/dist/export-bundle.js
CHANGED
|
@@ -52,6 +52,50 @@ export const ExportBundleSchema = z.object({
|
|
|
52
52
|
// renderer ("the cloud is dumb on purpose").
|
|
53
53
|
overview: z.array(OverviewPluginSchema)
|
|
54
54
|
});
|
|
55
|
+
// The bundle envelope with its two service arrays left unvalidated (validated per-entry so one bad entry
|
|
56
|
+
// doesn't reject the whole blob). Scalar top-level fields still fail hard.
|
|
57
|
+
const ExportBundleEnvelopeSchema = ExportBundleSchema.extend({
|
|
58
|
+
plugins: z.array(z.unknown()),
|
|
59
|
+
overview: z.array(z.unknown())
|
|
60
|
+
});
|
|
61
|
+
// Walk a value along a zod issue path, returning what the issue points at (undefined if the path runs off a
|
|
62
|
+
// null/absent branch) — lets us tell an absent field apart from a present-but-wrong one.
|
|
63
|
+
const valueAtPath = (value, path) => path.reduce((acc, key) => (acc == null ? undefined : acc[key]), value);
|
|
64
|
+
const serviceOf = (kind, item) => {
|
|
65
|
+
if (kind === 'overview') {
|
|
66
|
+
const o = item;
|
|
67
|
+
return o?.pluginId ?? o?.pluginName;
|
|
68
|
+
}
|
|
69
|
+
return item?.meta?.id;
|
|
70
|
+
};
|
|
71
|
+
// Validate one array's entries independently: keep the ones that parse, and turn each failure into a warning
|
|
72
|
+
// that names the service and flags absent fields (which usually mean the entry predates a schema addition).
|
|
73
|
+
const salvageEntries = (schema, items, kind) => {
|
|
74
|
+
const kept = [];
|
|
75
|
+
const warnings = [];
|
|
76
|
+
items.forEach((item, index) => {
|
|
77
|
+
const parsed = schema.safeParse(item);
|
|
78
|
+
if (parsed.success) {
|
|
79
|
+
kept.push(parsed.data);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const service = serviceOf(kind, item);
|
|
83
|
+
const label = `${kind}[${index}]${service ? ` (service '${service}')` : ''}`;
|
|
84
|
+
let anyAbsent = false;
|
|
85
|
+
const detail = parsed.error.issues
|
|
86
|
+
.map((i) => {
|
|
87
|
+
const absent = valueAtPath(item, i.path) === undefined;
|
|
88
|
+
anyAbsent ||= absent;
|
|
89
|
+
return `${i.path.join('.') || '(value)'}: ${i.message}`;
|
|
90
|
+
})
|
|
91
|
+
.join('; ');
|
|
92
|
+
const hint = anyAbsent
|
|
93
|
+
? " — a field is absent (this service's cached data predates it); refresh it and re-export"
|
|
94
|
+
: '';
|
|
95
|
+
warnings.push(`dropped ${label}: ${detail}${hint}`);
|
|
96
|
+
});
|
|
97
|
+
return { kept, warnings };
|
|
98
|
+
};
|
|
55
99
|
export const parseExportBundle = (raw) => {
|
|
56
100
|
const version = raw?.formatVersion;
|
|
57
101
|
if (typeof version === 'number' && version > EXPORT_BUNDLE_FORMAT_VERSION) {
|
|
@@ -60,9 +104,15 @@ export const parseExportBundle = (raw) => {
|
|
|
60
104
|
errors: [`bundle formatVersion ${version} is newer than this viewer supports (${EXPORT_BUNDLE_FORMAT_VERSION})`]
|
|
61
105
|
};
|
|
62
106
|
}
|
|
63
|
-
const
|
|
64
|
-
if (!
|
|
65
|
-
return { ok: false, errors:
|
|
107
|
+
const envelope = ExportBundleEnvelopeSchema.safeParse(raw);
|
|
108
|
+
if (!envelope.success) {
|
|
109
|
+
return { ok: false, errors: envelope.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`) };
|
|
66
110
|
}
|
|
67
|
-
|
|
111
|
+
const plugins = salvageEntries(ExportPluginSchema, envelope.data.plugins, 'plugins');
|
|
112
|
+
const overview = salvageEntries(OverviewPluginSchema, envelope.data.overview, 'overview');
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
bundle: { ...envelope.data, plugins: plugins.kept, overview: overview.kept },
|
|
116
|
+
warnings: [...plugins.warnings, ...overview.warnings]
|
|
117
|
+
};
|
|
68
118
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@butinapp/shapes",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Butin's host-layer data shapes built on the @butinapp/sdk data-view contract: the cross-service Overview input, the persisted ledger, the presentation manifest, and the portable export-bundle wire format.",
|
|
5
5
|
"homepage": "https://butin.app",
|
|
6
6
|
"bugs": "https://github.com/butinapp/butin/issues",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"lodash-es": "^4.18.1",
|
|
38
38
|
"luxon": "^3.7.2",
|
|
39
39
|
"zod": "^4.3.6",
|
|
40
|
-
"@butinapp/sdk": "0.1.
|
|
40
|
+
"@butinapp/sdk": "0.1.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"vitest": "^4.1.7"
|