@peers-app/peers-sdk 0.29.2 → 0.30.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/contracts/contract-resolvers.js +1 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/system/file-storage-contract.d.ts +76 -0
- package/dist/contracts/system/file-storage-contract.js +75 -0
- package/dist/contracts/system/files-contract.d.ts +5 -1
- package/dist/contracts/system/files-contract.js +50 -9
- package/dist/contracts/system/files-shared.d.ts +68 -3
- package/dist/contracts/system/files-shared.js +65 -5
- package/dist/contracts/validate.d.ts +1 -0
- package/dist/contracts/validate.js +6 -1
- package/dist/data/derived-row-id.d.ts +26 -0
- package/dist/data/derived-row-id.js +47 -0
- package/dist/data/files/chunk-store.d.ts +112 -0
- package/dist/data/files/chunk-store.js +107 -0
- package/dist/data/files/file-read-stream.d.ts +32 -3
- package/dist/data/files/file-read-stream.js +44 -29
- package/dist/data/files/file-rows.d.ts +68 -0
- package/dist/data/files/file-rows.js +158 -0
- package/dist/data/files/file-write-stream.d.ts +26 -0
- package/dist/data/files/file-write-stream.js +66 -42
- package/dist/data/files/file.types.d.ts +44 -23
- package/dist/data/files/file.types.js +33 -51
- package/dist/data/files/files.d.ts +27 -24
- package/dist/data/files/files.js +63 -85
- package/dist/data/files/index.d.ts +2 -0
- package/dist/data/files/index.js +2 -0
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/messages.d.ts +21 -0
- package/dist/data/messages.js +21 -1
- package/dist/data/orm/sql.data-source.d.ts +2 -1
- package/dist/data/orm/sql.data-source.js +1 -0
- package/dist/data/orm/types.js +12 -0
- package/dist/data/package-versions.js +3 -3
- package/dist/define/index.d.ts +1 -1
- package/dist/define/index.js +2 -1
- package/dist/define/system-contracts.d.ts +9 -2
- package/dist/define/system-contracts.js +6 -2
- package/dist/device-pairing/types.d.ts +2 -2
- package/dist/package-build/build-package.d.ts +12 -0
- package/dist/package-build/build-package.js +45 -6
- package/dist/package-build/cli.js +8 -0
- package/dist/package-build/contract-source.js +7 -5
- package/dist/package-installer/package-installer.d.ts +3 -5
- package/dist/package-installer/package-installer.js +5 -21
- package/dist/package-installer/package-propagation.js +6 -17
- package/dist/system-ids.d.ts +2 -0
- package/dist/system-ids.js +3 -1
- package/dist/types/field-type.d.ts +14 -0
- package/dist/types/field-type.js +14 -1
- package/dist/types/zod-types.d.ts +10 -0
- package/dist/types/zod-types.js +25 -7
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.loadPackageModule = loadPackageModule;
|
|
4
|
+
exports.fileFieldWarnings = fileFieldWarnings;
|
|
4
5
|
exports.generatePackageManifest = generatePackageManifest;
|
|
5
6
|
exports.packageManifest = packageManifest;
|
|
6
7
|
exports.buildPackage = buildPackage;
|
|
@@ -18,6 +19,7 @@ const node_module_1 = require("node:module");
|
|
|
18
19
|
const path = require("node:path");
|
|
19
20
|
const manifest_1 = require("../define/manifest");
|
|
20
21
|
const isolated_artifact_1 = require("../package-loader/isolated-artifact");
|
|
22
|
+
const field_type_1 = require("../types/field-type");
|
|
21
23
|
const freeze_contracts_1 = require("./freeze-contracts");
|
|
22
24
|
/** Source text SES rejects before running it, with what to tell the author. */
|
|
23
25
|
const SES_REJECTED_PATTERNS = [
|
|
@@ -129,7 +131,38 @@ async function loadModule(options, entry) {
|
|
|
129
131
|
function validateManifest(manifest, providerSource = "void 0;") {
|
|
130
132
|
(0, isolated_artifact_1.validateIsolatedPackageArtifact)({ manifest: structuredClone(manifest), providerSource }, { strict: true });
|
|
131
133
|
}
|
|
132
|
-
/**
|
|
134
|
+
/** A field name that reads as a file id: `fileId`, `imageFileId`, `fileIds` (not `profileId`). */
|
|
135
|
+
const FILE_ID_NAME = /(?:^file|File)Ids?$/;
|
|
136
|
+
/**
|
|
137
|
+
* Warnings about table fields that look like file references but aren't: a top-level field
|
|
138
|
+
* named like a file id that isn't declared with `zodFileId`, and a `zodFileId` nested in an
|
|
139
|
+
* object field. Neither keeps its files, so Peers may free them. Internal to the build.
|
|
140
|
+
*
|
|
141
|
+
* @internal
|
|
142
|
+
* @param manifest - The package's manifest.
|
|
143
|
+
*/
|
|
144
|
+
function fileFieldWarnings(manifest) {
|
|
145
|
+
const warnings = [];
|
|
146
|
+
const nested = (table, fields, parent) => {
|
|
147
|
+
for (const field of fields ?? []) {
|
|
148
|
+
const path = `${parent}.${field.name}`;
|
|
149
|
+
if ((0, field_type_1.isFileReferenceField)(field)) {
|
|
150
|
+
warnings.push(`Table ${table}: "${path}" is a zodFileId inside an object field, which doesn't keep its files. Only a table's top-level fields do: move it up, or use a table of attachments.`);
|
|
151
|
+
}
|
|
152
|
+
nested(table, field.fields, path);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
for (const table of manifest.tables ?? []) {
|
|
156
|
+
for (const field of table.fields) {
|
|
157
|
+
if (FILE_ID_NAME.test(field.name) && !(0, field_type_1.isFileReferenceField)(field)) {
|
|
158
|
+
warnings.push(`Table ${table.name}: "${field.name}" looks like a file id but isn't declared with zodFileId, so it doesn't keep its files. Declare it with zodFileId and raise the table's versionNumber.`);
|
|
159
|
+
}
|
|
160
|
+
nested(table.name, field.fields, field.name);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return warnings;
|
|
164
|
+
}
|
|
165
|
+
/** The package's definition and manifest, validated together, and the build's warnings. */
|
|
133
166
|
async function validPackage(options) {
|
|
134
167
|
// frozen-contracts.json gives the shapes of older versions a contract also implements.
|
|
135
168
|
const definition = await loadDefinition(options);
|
|
@@ -137,7 +170,7 @@ async function validPackage(options) {
|
|
|
137
170
|
frozen: await (0, freeze_contracts_1.readFrozenContracts)(options.root),
|
|
138
171
|
});
|
|
139
172
|
validateManifest(manifest);
|
|
140
|
-
return { definition, manifest };
|
|
173
|
+
return { definition, manifest, warnings: fileFieldWarnings(manifest) };
|
|
141
174
|
}
|
|
142
175
|
/** The package's manifest, validated and checked against the contracts it froze. */
|
|
143
176
|
async function checkedPackage(options) {
|
|
@@ -146,8 +179,8 @@ async function checkedPackage(options) {
|
|
|
146
179
|
return result;
|
|
147
180
|
}
|
|
148
181
|
async function writeManifest(options) {
|
|
149
|
-
const { manifest } = await checkedPackage(options);
|
|
150
|
-
return saveManifest(options, manifest);
|
|
182
|
+
const { manifest, warnings } = await checkedPackage(options);
|
|
183
|
+
return { ...(await saveManifest(options, manifest)), warnings };
|
|
151
184
|
}
|
|
152
185
|
async function saveManifest(options, manifest) {
|
|
153
186
|
const manifestPath = path.join(options.outDir, "manifest.json");
|
|
@@ -241,7 +274,7 @@ async function packageManifest(buildOptions = {}) {
|
|
|
241
274
|
*/
|
|
242
275
|
async function buildPackage(buildOptions = {}) {
|
|
243
276
|
const options = resolveOptions(buildOptions);
|
|
244
|
-
const { definition, manifest } = await checkedPackage(options);
|
|
277
|
+
const { definition, manifest, warnings } = await checkedPackage(options);
|
|
245
278
|
const hasProvider = definition.provides.length > 0 ||
|
|
246
279
|
definition.tables.length > 0 ||
|
|
247
280
|
definition.startHooks.length > 0 ||
|
|
@@ -252,7 +285,13 @@ async function buildPackage(buildOptions = {}) {
|
|
|
252
285
|
const providerSource = output?.outputFiles?.[0]?.text ?? "";
|
|
253
286
|
const artifactPath = await writeArtifact(options, manifest, providerSource);
|
|
254
287
|
const { manifestPath } = await saveManifest(options, manifest);
|
|
255
|
-
return {
|
|
288
|
+
return {
|
|
289
|
+
manifest,
|
|
290
|
+
manifestPath,
|
|
291
|
+
artifactPath,
|
|
292
|
+
providerChars: providerSource.length,
|
|
293
|
+
warnings,
|
|
294
|
+
};
|
|
256
295
|
}
|
|
257
296
|
/**
|
|
258
297
|
* Build once, then rebuild whenever a source file changes. Resolves once watching starts.
|
|
@@ -64,6 +64,11 @@ function summarize(result) {
|
|
|
64
64
|
const tools = manifest.provides.reduce((count, contract) => count + contract.tools.length, 0);
|
|
65
65
|
return `${manifest.provides.length} contract(s), ${tools} tool(s), ${manifest.tables?.length ?? 0} table(s)`;
|
|
66
66
|
}
|
|
67
|
+
/** Print the build's warnings, one per line. */
|
|
68
|
+
function printWarnings(result) {
|
|
69
|
+
for (const warning of result.warnings)
|
|
70
|
+
console.warn(`Warning: ${warning}`);
|
|
71
|
+
}
|
|
67
72
|
function relative(file) {
|
|
68
73
|
return path.relative(process.cwd(), file) || file;
|
|
69
74
|
}
|
|
@@ -88,6 +93,7 @@ async function main(argv) {
|
|
|
88
93
|
throw new Error("--watch applies to build");
|
|
89
94
|
}
|
|
90
95
|
const result = await (0, build_package_1.generatePackageManifest)(options);
|
|
96
|
+
printWarnings(result);
|
|
91
97
|
console.log(`Manifest: ${summarize(result)} -> ${relative(result.manifestPath)}`);
|
|
92
98
|
return 0;
|
|
93
99
|
}
|
|
@@ -97,12 +103,14 @@ async function main(argv) {
|
|
|
97
103
|
console.error(`Build failed: ${result.message}`);
|
|
98
104
|
return;
|
|
99
105
|
}
|
|
106
|
+
printWarnings(result);
|
|
100
107
|
console.log(`Built ${relative(result.artifactPath)} (${summarize(result)}; SDK ${sdk_version_1.SDK_VERSION}; provider ${Math.round(result.providerChars / 1024)} KB)`);
|
|
101
108
|
});
|
|
102
109
|
console.log("Watching for changes");
|
|
103
110
|
return new Promise(() => undefined);
|
|
104
111
|
}
|
|
105
112
|
const result = await (0, build_package_1.buildPackage)(options);
|
|
113
|
+
printWarnings(result);
|
|
106
114
|
console.log(`Built ${relative(result.artifactPath)} (${summarize(result)}; SDK ${sdk_version_1.SDK_VERSION}; provider ${Math.round(result.providerChars / 1024)} KB)`);
|
|
107
115
|
return 0;
|
|
108
116
|
}
|
|
@@ -316,7 +316,7 @@ class Code {
|
|
|
316
316
|
(field.enumValues !== undefined &&
|
|
317
317
|
new Set(field.enumValues).size !== field.enumValues.length) ||
|
|
318
318
|
field.defaultValue !== undefined ||
|
|
319
|
-
field.subType !== undefined ||
|
|
319
|
+
(field.subType !== undefined && !(0, field_type_1.isFileReferenceField)(field)) ||
|
|
320
320
|
field.optional === false ||
|
|
321
321
|
field.isArray === false ||
|
|
322
322
|
field.description === "") {
|
|
@@ -367,11 +367,13 @@ class Code {
|
|
|
367
367
|
return values?.length && new Set(values).size === 1
|
|
368
368
|
? `z.literal(${JSON.stringify(values[0])})`
|
|
369
369
|
: "z.boolean()";
|
|
370
|
-
case field_type_1.FieldType.id:
|
|
371
|
-
|
|
370
|
+
case field_type_1.FieldType.id: {
|
|
371
|
+
const idSchema = (0, field_type_1.isFileReferenceField)(field) ? "zodFileId" : "zodPeerId";
|
|
372
|
+
this.imports.add(idSchema);
|
|
372
373
|
return values?.length
|
|
373
|
-
?
|
|
374
|
-
:
|
|
374
|
+
? `${idSchema}.refine((value) => ${JSON.stringify(values)}.includes(value))`
|
|
375
|
+
: idSchema;
|
|
376
|
+
}
|
|
375
377
|
case field_type_1.FieldType.Date:
|
|
376
378
|
return "z.date()";
|
|
377
379
|
case field_type_1.FieldType.blob:
|
|
@@ -37,11 +37,9 @@ export declare function ensurePackageVersionAppNavs(dataContext: DataContext, de
|
|
|
37
37
|
*/
|
|
38
38
|
export declare function installAllPackageBundles(dataContext: DataContext, deps: IPackageInstallerDeps): Promise<void>;
|
|
39
39
|
/**
|
|
40
|
-
* Save a bundle's content as a
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* the existing record is reused — no new File is created. This eliminates
|
|
44
|
-
* the "new File record on every dev reload" bug.
|
|
40
|
+
* Save a bundle's content as a file the runtime owns: collected once no package version
|
|
41
|
+
* references it. The same content and name give the same file, so a rebuild with no change
|
|
42
|
+
* adds no row, and every save stores the chunks again (restoring any a device has freed).
|
|
45
43
|
*/
|
|
46
44
|
export declare function saveBundleFile(dataContext: DataContext, content: string, name: string, _packageId: string): Promise<{
|
|
47
45
|
fileId: string;
|
|
@@ -98,7 +98,7 @@ async function installPackageFromBundles(dataContext, deps, packageId, opts) {
|
|
|
98
98
|
});
|
|
99
99
|
return { packageVersion: existingPv, loaded, unchanged, warning };
|
|
100
100
|
}
|
|
101
|
-
// 7. Save bundle files (
|
|
101
|
+
// 7. Save bundle files (the same content and name is the same file)
|
|
102
102
|
const packageFile = await saveBundleFile(dataContext, packageBundle, `${packageId}-package.bundle.js`, packageId);
|
|
103
103
|
let routesFile;
|
|
104
104
|
if (routesBundle) {
|
|
@@ -278,28 +278,12 @@ async function installAllPackageBundles(dataContext, deps) {
|
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
/**
|
|
281
|
-
* Save a bundle's content as a
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
* the existing record is reused — no new File is created. This eliminates
|
|
285
|
-
* the "new File record on every dev reload" bug.
|
|
281
|
+
* Save a bundle's content as a file the runtime owns: collected once no package version
|
|
282
|
+
* references it. The same content and name give the same file, so a rebuild with no change
|
|
283
|
+
* adds no row, and every save stores the chunks again (restoring any a device has freed).
|
|
286
284
|
*/
|
|
287
285
|
async function saveBundleFile(dataContext, content, name, _packageId) {
|
|
288
|
-
const
|
|
289
|
-
const filesTable = (0, files_1.Files)(dataContext);
|
|
290
|
-
// Check if a file with this hash already exists for this bundle name
|
|
291
|
-
const existing = await filesTable.findOne({ name, fileHash });
|
|
292
|
-
if (existing) {
|
|
293
|
-
return { fileId: existing.fileId, fileHash: existing.fileHash };
|
|
294
|
-
}
|
|
295
|
-
const fileId = (0, utils_1.newid)();
|
|
296
|
-
const metadata = {
|
|
297
|
-
fileId,
|
|
298
|
-
name,
|
|
299
|
-
fileSize: content.length,
|
|
300
|
-
mimeType: "application/javascript",
|
|
301
|
-
};
|
|
302
|
-
const saved = await filesTable.saveFile(metadata, content);
|
|
286
|
+
const saved = await (0, files_1.Files)(dataContext).saveFile({ name, mimeType: "application/javascript", keep: false }, content);
|
|
303
287
|
return { fileId: saved.fileId, fileHash: saved.fileHash };
|
|
304
288
|
}
|
|
305
289
|
/**
|
|
@@ -125,7 +125,7 @@ async function installPvInGroupNoActivate(source, dest, pv) {
|
|
|
125
125
|
if (!files)
|
|
126
126
|
return false;
|
|
127
127
|
for (const file of files) {
|
|
128
|
-
await
|
|
128
|
+
await copyBundleRow(dest, file);
|
|
129
129
|
}
|
|
130
130
|
const propagatedPv = buildPropagatedPv(pv, files);
|
|
131
131
|
await (0, package_versions_1.PackageVersions)(dest).signAndSave(propagatedPv, {
|
|
@@ -162,9 +162,9 @@ async function installPvInGroup(source, dest, pv, retryCnt = 0) {
|
|
|
162
162
|
if (!files) {
|
|
163
163
|
return await retryOrFail(source, dest, pv, retryCnt, "missing files");
|
|
164
164
|
}
|
|
165
|
-
// Copy
|
|
165
|
+
// Copy the bundles' rows into the destination
|
|
166
166
|
for (const file of files) {
|
|
167
|
-
await
|
|
167
|
+
await copyBundleRow(dest, file);
|
|
168
168
|
}
|
|
169
169
|
// Save sanitized PV
|
|
170
170
|
const propagatedPv = buildPropagatedPv(pv, files);
|
|
@@ -231,20 +231,9 @@ async function copyBundleFiles(source, pv) {
|
|
|
231
231
|
}
|
|
232
232
|
return bundles;
|
|
233
233
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
async function saveFileAndIndexTree(sourceFiles, destFiles, file, copiedIds) {
|
|
238
|
-
if (copiedIds.has(file.fileId))
|
|
239
|
-
return;
|
|
240
|
-
copiedIds.add(file.fileId);
|
|
241
|
-
if (file.indexFileId) {
|
|
242
|
-
const indexFile = await sourceFiles.get(file.indexFileId);
|
|
243
|
-
if (indexFile) {
|
|
244
|
-
await saveFileAndIndexTree(sourceFiles, destFiles, indexFile, copiedIds);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
await destFiles.saveFileRecord(file);
|
|
234
|
+
/** Copy a bundle's row into `dest`. It keeps its id: a file's id doesn't depend on its context. */
|
|
235
|
+
async function copyBundleRow(dest, bundle) {
|
|
236
|
+
await (0, files_1.Files)(dest).saveFileRecord(bundle.file);
|
|
248
237
|
}
|
|
249
238
|
/** Select the best publisher-signed release under an Admin-approved package's follow policy. */
|
|
250
239
|
async function activateBestEligibleVersion(dataContext, pkg) {
|
package/dist/system-ids.d.ts
CHANGED
|
@@ -217,3 +217,5 @@ export declare const hostShellContractId = "00mveexhw7ezjfghxomlo011g";
|
|
|
217
217
|
export declare const groupMembersContractId = "00mvzfzkuf4djwjrsxq9cnaxt";
|
|
218
218
|
/** Local-only System Files v1: save and read files in the caller's own context; allocated once with newid(). */
|
|
219
219
|
export declare const filesContractId = "00mw1pvs1eupopu6sttetmki0";
|
|
220
|
+
/** Local-only System File Storage v1: this device's chunk store and its migration; allocated once with newid(). */
|
|
221
|
+
export declare const fileStorageContractId = "00mw2svtlb4yv8opod7vnofgn";
|
package/dist/system-ids.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.filesContractId = exports.groupMembersContractId = exports.hostShellContractId = exports.packagesContractId = exports.desktopToolsContractId = exports.hostToolsContractId = exports.toolCatalogContractId = exports.schedulerToolIds = exports.schedulerContractId = exports.contractCatalogToolIds = exports.contractCatalogContractId = exports.httpToolIds = exports.httpContractId = exports.localFoldersToolIds = exports.localFoldersContractId = exports.identityToolIds = exports.identityContractId = exports.invitesToolIds = exports.invitesContractId = exports.toolAccessControlToolIds = exports.toolAccessControlContractId = exports.syncCheckContractId = exports.appUpdatesContractId = exports.networkControlContractId = exports.networkDiagnosticsContractId = exports.deviceOperationsContractId = exports.logsContractId = exports.peersSystemPackageId = exports.peersCoreRevokedPublishPublicKeys = exports.peersCorePublishPublicKey = exports.peersCorePackageRepoUrl = exports.peersCorePackageId = exports.createGroupToolId = exports.queryDatabaseToolId = exports.runWorkflowToolId = exports.defaultSendMessageToolId = exports.defaultAssistantRunnerToolId = exports.adminAssistantId = exports.openCodeAssistantId = exports.defaultAssistantId = exports.peersRootUserId = void 0;
|
|
3
|
+
exports.fileStorageContractId = exports.filesContractId = exports.groupMembersContractId = exports.hostShellContractId = exports.packagesContractId = exports.desktopToolsContractId = exports.hostToolsContractId = exports.toolCatalogContractId = exports.schedulerToolIds = exports.schedulerContractId = exports.contractCatalogToolIds = exports.contractCatalogContractId = exports.httpToolIds = exports.httpContractId = exports.localFoldersToolIds = exports.localFoldersContractId = exports.identityToolIds = exports.identityContractId = exports.invitesToolIds = exports.invitesContractId = exports.toolAccessControlToolIds = exports.toolAccessControlContractId = exports.syncCheckContractId = exports.appUpdatesContractId = exports.networkControlContractId = exports.networkDiagnosticsContractId = exports.deviceOperationsContractId = exports.logsContractId = exports.peersSystemPackageId = exports.peersCoreRevokedPublishPublicKeys = exports.peersCorePublishPublicKey = exports.peersCorePackageRepoUrl = exports.peersCorePackageId = exports.createGroupToolId = exports.queryDatabaseToolId = exports.runWorkflowToolId = exports.defaultSendMessageToolId = exports.defaultAssistantRunnerToolId = exports.adminAssistantId = exports.openCodeAssistantId = exports.defaultAssistantId = exports.peersRootUserId = void 0;
|
|
4
4
|
/** Stable user ID that owns built-in Peers system records. */
|
|
5
5
|
exports.peersRootUserId = "000peers0user000000000001";
|
|
6
6
|
/** Default assistant used when no user-selected assistant is available. */
|
|
@@ -224,3 +224,5 @@ exports.hostShellContractId = "00mveexhw7ezjfghxomlo011g";
|
|
|
224
224
|
exports.groupMembersContractId = "00mvzfzkuf4djwjrsxq9cnaxt";
|
|
225
225
|
/** Local-only System Files v1: save and read files in the caller's own context; allocated once with newid(). */
|
|
226
226
|
exports.filesContractId = "00mw1pvs1eupopu6sttetmki0";
|
|
227
|
+
/** Local-only System File Storage v1: this device's chunk store and its migration; allocated once with newid(). */
|
|
228
|
+
exports.fileStorageContractId = "00mw2svtlb4yv8opod7vnofgn";
|
|
@@ -32,6 +32,10 @@ export interface IField {
|
|
|
32
32
|
optional?: boolean;
|
|
33
33
|
/** The value is an array of `type`; `fields`, `enumValues` describe each element. */
|
|
34
34
|
isArray?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* What the value means beyond its type. {@link FILE_SUBTYPE} on an `id` field makes it a file
|
|
37
|
+
* reference ({@link isFileReferenceField}); `"markdown"` on a string asks UIs to render it.
|
|
38
|
+
*/
|
|
35
39
|
subType?: string;
|
|
36
40
|
/** An object's own fields. Absent: any object. Only on `object`; other keys may be present. */
|
|
37
41
|
fields?: IField[];
|
|
@@ -52,3 +56,13 @@ export declare const fieldSchema: z.ZodObject<{
|
|
|
52
56
|
fields: z.ZodOptional<z.ZodLazy<z.ZodArray<z.ZodType<IField>>>>;
|
|
53
57
|
enumValues: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
54
58
|
}, "strip", z.ZodTypeAny, IField, IField>;
|
|
59
|
+
/** The {@link IField.subType} of an `id` field that names a file: what `zodFileId` declares. */
|
|
60
|
+
export declare const FILE_SUBTYPE = "file";
|
|
61
|
+
/**
|
|
62
|
+
* True when a table field references files: an `id` field, or an array of them, with
|
|
63
|
+
* {@link FILE_SUBTYPE}. Only a table's top-level fields count; a file id nested in an object
|
|
64
|
+
* field isn't a reference.
|
|
65
|
+
*
|
|
66
|
+
* @param field - One of a table definition's top-level fields.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isFileReferenceField(field: Pick<IField, "type" | "subType">): boolean;
|
package/dist/types/field-type.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fieldSchema = exports.FieldType = void 0;
|
|
3
|
+
exports.FILE_SUBTYPE = exports.fieldSchema = exports.FieldType = void 0;
|
|
4
|
+
exports.isFileReferenceField = isFileReferenceField;
|
|
4
5
|
const zod_1 = require("zod");
|
|
5
6
|
//export type FieldType = 'id' | 'string' | 'number' | 'boolean' | 'Date' | 'object' | 'blob' | 'any';
|
|
6
7
|
/** The value types a Peers IR field can have. */
|
|
@@ -27,3 +28,15 @@ exports.fieldSchema = zod_1.z.object({
|
|
|
27
28
|
fields: zod_1.z.lazy(() => zod_1.z.array(exports.fieldSchema)).optional(),
|
|
28
29
|
enumValues: zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])).optional(),
|
|
29
30
|
});
|
|
31
|
+
/** The {@link IField.subType} of an `id` field that names a file: what `zodFileId` declares. */
|
|
32
|
+
exports.FILE_SUBTYPE = "file";
|
|
33
|
+
/**
|
|
34
|
+
* True when a table field references files: an `id` field, or an array of them, with
|
|
35
|
+
* {@link FILE_SUBTYPE}. Only a table's top-level fields count; a file id nested in an object
|
|
36
|
+
* field isn't a reference.
|
|
37
|
+
*
|
|
38
|
+
* @param field - One of a table definition's top-level fields.
|
|
39
|
+
*/
|
|
40
|
+
function isFileReferenceField(field) {
|
|
41
|
+
return field.type === FieldType.id && field.subType === exports.FILE_SUBTYPE;
|
|
42
|
+
}
|
|
@@ -9,6 +9,16 @@ export declare const zodAnyObjectOrArray: z.ZodUnion<[z.ZodObject<{}, "strip", z
|
|
|
9
9
|
* records the field as an id.
|
|
10
10
|
*/
|
|
11
11
|
export declare const zodPeerId: z.ZodEffects<z.ZodString, string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* A file's id, as `SystemFiles.save` returns it: a {@link zodPeerId} marked as a file reference
|
|
14
|
+
* (`subType: "file"`). A synced table's top-level field declared with it, or with an array of it,
|
|
15
|
+
* keeps the files it names: Peers frees a file's bytes only some time after no such field names
|
|
16
|
+
* it. Local-only tables, package variables, plain string fields, and nested object fields
|
|
17
|
+
* don't declare references.
|
|
18
|
+
*
|
|
19
|
+
* Changing a field to `zodFileId` changes the table's definition, so raise its `versionNumber`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const zodFileId: z.ZodEffects<z.ZodString, string, string>;
|
|
12
22
|
/** Any zod object schema. */
|
|
13
23
|
export type ZodObjectType = z.ZodObject<any>;
|
|
14
24
|
/** Any zod array schema. */
|
package/dist/types/zod-types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.zodPeerId = exports.zodAnyObjectOrArray = exports.zodAnyObject = exports.z = void 0;
|
|
3
|
+
exports.zodFileId = exports.zodPeerId = exports.zodAnyObjectOrArray = exports.zodAnyObject = exports.z = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const peer_id_1 = require("../peer-id");
|
|
6
6
|
const field_type_1 = require("./field-type");
|
|
@@ -14,13 +14,31 @@ Object.defineProperty(exports, "z", { enumerable: true, get: function () { retur
|
|
|
14
14
|
exports.zodAnyObject = zod_1.z.object({}).catchall(zod_1.z.any());
|
|
15
15
|
/** Any plain object or any array. */
|
|
16
16
|
exports.zodAnyObjectOrArray = zod_1.z.union([exports.zodAnyObject, zod_1.z.array(zod_1.z.any())]);
|
|
17
|
+
/** A new peer-id schema, marked as {@link FieldType.id} and, given one, a subtype. */
|
|
18
|
+
function peerIdSchema(subType) {
|
|
19
|
+
const schema = zod_1.z.string().refine((value) => {
|
|
20
|
+
return (0, peer_id_1.isid)(value);
|
|
21
|
+
}, {
|
|
22
|
+
message: "Invalid peer id, it must be a 25 character alphanumeric string",
|
|
23
|
+
});
|
|
24
|
+
schema._def._fieldType = field_type_1.FieldType.id;
|
|
25
|
+
if (subType) {
|
|
26
|
+
schema._def._subType = subType;
|
|
27
|
+
}
|
|
28
|
+
return schema;
|
|
29
|
+
}
|
|
17
30
|
/**
|
|
18
31
|
* A 25-character peer id from `newid()`. Marked as {@link FieldType.id}, so `schemaToFields`
|
|
19
32
|
* records the field as an id.
|
|
20
33
|
*/
|
|
21
|
-
exports.zodPeerId =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
exports.zodPeerId = peerIdSchema();
|
|
35
|
+
/**
|
|
36
|
+
* A file's id, as `SystemFiles.save` returns it: a {@link zodPeerId} marked as a file reference
|
|
37
|
+
* (`subType: "file"`). A synced table's top-level field declared with it, or with an array of it,
|
|
38
|
+
* keeps the files it names: Peers frees a file's bytes only some time after no such field names
|
|
39
|
+
* it. Local-only tables, package variables, plain string fields, and nested object fields
|
|
40
|
+
* don't declare references.
|
|
41
|
+
*
|
|
42
|
+
* Changing a field to `zodFileId` changes the table's definition, so raise its `versionNumber`.
|
|
43
|
+
*/
|
|
44
|
+
exports.zodFileId = peerIdSchema(field_type_1.FILE_SUBTYPE);
|