@peers-app/peers-sdk 0.28.10 → 0.28.12
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/group-members-contract.d.ts +25 -0
- package/dist/contracts/system/group-members-contract.js +50 -0
- package/dist/data/authority-write-checks.d.ts +58 -1
- package/dist/data/authority-write-checks.js +176 -1
- package/dist/data/group-resign.d.ts +30 -0
- package/dist/data/group-resign.js +74 -0
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/orm/index.d.ts +1 -0
- package/dist/data/orm/index.js +1 -0
- package/dist/data/orm/signed-package-table.d.ts +126 -0
- package/dist/data/orm/signed-package-table.js +293 -0
- package/dist/data/orm/table-container.d.ts +22 -2
- package/dist/data/orm/table-container.js +49 -14
- package/dist/data/orm/types.d.ts +12 -0
- package/dist/data/package-table-identity.d.ts +48 -0
- package/dist/data/package-table-identity.js +151 -0
- package/dist/data/signed-row-id.d.ts +43 -0
- package/dist/data/signed-row-id.js +72 -0
- package/dist/define/manifest.js +3 -1
- package/dist/define/system-contracts.d.ts +99 -0
- package/dist/define/system-contracts.js +5 -1
- package/dist/define/table.d.ts +32 -0
- package/dist/define/table.js +120 -2
- package/dist/invites/invite-messages.d.ts +44 -44
- package/dist/package-loader/isolated-artifact.d.ts +15 -0
- package/dist/package-loader/isolated-artifact.js +12 -1
- package/dist/package-loader/isolated-runtime.d.ts +4 -0
- package/dist/package-loader/isolated-table-gateway.js +31 -3
- package/dist/system-ids.d.ts +2 -0
- package/dist/system-ids.js +3 -1
- package/package.json +1 -1
package/dist/define/table.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PackageTable = void 0;
|
|
4
4
|
exports.defineTable = defineTable;
|
|
5
|
+
const signed_row_id_1 = require("../data/signed-row-id");
|
|
5
6
|
const isolated_runtime_1 = require("../package-loader/isolated-runtime");
|
|
7
|
+
const field_type_1 = require("../types/field-type");
|
|
6
8
|
const empty_fields_1 = require("./empty-fields");
|
|
7
9
|
const table_handle_1 = require("./table-handle");
|
|
8
10
|
/**
|
|
@@ -120,6 +122,102 @@ class PackageTable {
|
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
124
|
exports.PackageTable = PackageTable;
|
|
125
|
+
/** The columns Peers adds to a signed table; a schema can't declare them. */
|
|
126
|
+
const SIGNED_TABLE_COLUMNS = [
|
|
127
|
+
"signature",
|
|
128
|
+
"signedAt",
|
|
129
|
+
"signedContextId",
|
|
130
|
+
"signedTableId",
|
|
131
|
+
"signedIdSeed",
|
|
132
|
+
];
|
|
133
|
+
/** The field types a signed table's key fields may have. */
|
|
134
|
+
const SIGNED_KEY_TYPES = new Set([
|
|
135
|
+
field_type_1.FieldType.string,
|
|
136
|
+
field_type_1.FieldType.id,
|
|
137
|
+
field_type_1.FieldType.number,
|
|
138
|
+
field_type_1.FieldType.boolean,
|
|
139
|
+
]);
|
|
140
|
+
/**
|
|
141
|
+
* A schema field's Peers field type and whether a wrapper makes it optional, nullable, an
|
|
142
|
+
* array, or defaulted. `zodPeerId` marks its own def (a refinement) as an id field; walk the
|
|
143
|
+
* wrappers the manifest walks and take the mark from whichever level carries it.
|
|
144
|
+
*/
|
|
145
|
+
function schemaFieldKind(schema, name) {
|
|
146
|
+
let def = schema.shape[name]._def;
|
|
147
|
+
let wrapped = false;
|
|
148
|
+
let isArray = false;
|
|
149
|
+
let fieldType = def._fieldType;
|
|
150
|
+
const typeName = () => def.typeName;
|
|
151
|
+
while (def.innerType || def.schema || def.type) {
|
|
152
|
+
isArray ||= typeName() === "ZodArray";
|
|
153
|
+
wrapped ||= ["ZodOptional", "ZodNullable", "ZodArray", "ZodDefault"].includes(typeName());
|
|
154
|
+
def = (def.innerType ?? def.schema ?? def.type)._def;
|
|
155
|
+
fieldType ??= def._fieldType;
|
|
156
|
+
}
|
|
157
|
+
fieldType ??= {
|
|
158
|
+
ZodString: field_type_1.FieldType.string,
|
|
159
|
+
ZodEnum: field_type_1.FieldType.string,
|
|
160
|
+
ZodNumber: field_type_1.FieldType.number,
|
|
161
|
+
ZodBoolean: field_type_1.FieldType.boolean,
|
|
162
|
+
}[typeName()];
|
|
163
|
+
// A literal is typed by its value, as the manifest types it.
|
|
164
|
+
if (!fieldType && typeName() === "ZodLiteral") {
|
|
165
|
+
fieldType = { string: field_type_1.FieldType.string, number: field_type_1.FieldType.number, boolean: field_type_1.FieldType.boolean }[typeof def.value];
|
|
166
|
+
}
|
|
167
|
+
return { fieldType, wrapped, isArray };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Check a `signedBy` declaration without the manifest machinery (this entry stays small): the
|
|
171
|
+
* owner field and the primary key are required, single `zodPeerId` fields and differ; any
|
|
172
|
+
* `signedKey` fields are distinct, required scalars other than those two; the table isn't
|
|
173
|
+
* local-only; and the schema leaves the signature columns to Peers. The build checks the
|
|
174
|
+
* manifest again.
|
|
175
|
+
*/
|
|
176
|
+
function validateSignedByField(definition) {
|
|
177
|
+
const { name, signedBy, signedKey, schema, localOnly, primaryKeyName } = definition;
|
|
178
|
+
const label = `Table ${name}`;
|
|
179
|
+
if (typeof signedBy !== "string" || !(signedBy in schema.shape)) {
|
|
180
|
+
throw new Error(`${label}.signedBy names a field the table doesn't have: "${signedBy}"`);
|
|
181
|
+
}
|
|
182
|
+
const owner = schemaFieldKind(schema, signedBy);
|
|
183
|
+
if (owner.wrapped || owner.fieldType !== field_type_1.FieldType.id) {
|
|
184
|
+
throw new Error(`${label}.signedBy must name a required field of type id, a user id`);
|
|
185
|
+
}
|
|
186
|
+
if (localOnly) {
|
|
187
|
+
throw new Error(`${label}.signedBy can't be set on a local-only table: nothing syncs`);
|
|
188
|
+
}
|
|
189
|
+
if (primaryKeyName === signedBy) {
|
|
190
|
+
throw new Error(`${label}: a signed table's primary key can't be its owner field; use signedKey: [] for one row per owner`);
|
|
191
|
+
}
|
|
192
|
+
const primaryKey = schemaFieldKind(schema, primaryKeyName);
|
|
193
|
+
if (primaryKey.fieldType !== field_type_1.FieldType.id || primaryKey.isArray) {
|
|
194
|
+
throw new Error(`${label}: a signed table's primary key must be a zodPeerId`);
|
|
195
|
+
}
|
|
196
|
+
if (signedKey !== undefined) {
|
|
197
|
+
if (!Array.isArray(signedKey))
|
|
198
|
+
throw new Error(`${label}.signedKey must be a list of fields`);
|
|
199
|
+
const seen = new Set();
|
|
200
|
+
for (const field of signedKey) {
|
|
201
|
+
if (typeof field !== "string" || !(field in schema.shape)) {
|
|
202
|
+
throw new Error(`${label}.signedKey names a field the table doesn't have: "${field}"`);
|
|
203
|
+
}
|
|
204
|
+
if (seen.has(field))
|
|
205
|
+
throw new Error(`${label}.signedKey lists "${field}" twice`);
|
|
206
|
+
seen.add(field);
|
|
207
|
+
if (field === primaryKeyName || field === signedBy) {
|
|
208
|
+
throw new Error(`${label}.signedKey can't list "${field}": the owner and the id are already part of a row's identity`);
|
|
209
|
+
}
|
|
210
|
+
const kind = schemaFieldKind(schema, field);
|
|
211
|
+
if (kind.wrapped || !kind.fieldType || !SIGNED_KEY_TYPES.has(kind.fieldType)) {
|
|
212
|
+
throw new Error(`${label}.signedKey field "${field}" must be a required string, id, number, or boolean`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const reserved = SIGNED_TABLE_COLUMNS.find((column) => column in schema.shape);
|
|
217
|
+
if (reserved) {
|
|
218
|
+
throw new Error(`${label} declares "${reserved}", which the host adds to a signed table itself`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
123
221
|
/**
|
|
124
222
|
* Declare one of the package's tables from a zod schema.
|
|
125
223
|
*
|
|
@@ -138,12 +236,32 @@ function defineTable(definition) {
|
|
|
138
236
|
if (!(definition.primaryKeyName in definition.schema.shape)) {
|
|
139
237
|
throw new Error(`Table ${definition.name} primary key "${definition.primaryKeyName}" is not in its schema`);
|
|
140
238
|
}
|
|
239
|
+
if (definition.signedBy !== undefined) {
|
|
240
|
+
validateSignedByField(definition);
|
|
241
|
+
}
|
|
242
|
+
else if (definition.signedKey !== undefined) {
|
|
243
|
+
throw new Error(`Table ${definition.name}.signedKey needs signedBy`);
|
|
244
|
+
}
|
|
141
245
|
const TableClass = definition.tableClass ?? PackageTable;
|
|
142
246
|
if (typeof TableClass !== "function" ||
|
|
143
247
|
!(TableClass.prototype instanceof PackageTable || TableClass === PackageTable)) {
|
|
144
248
|
throw new Error(`Table ${definition.name} tableClass must extend PackageTable`);
|
|
145
249
|
}
|
|
146
|
-
const frozen = Object.freeze({
|
|
250
|
+
const frozen = Object.freeze({
|
|
251
|
+
...definition,
|
|
252
|
+
...(definition.signedKey ? { signedKey: Object.freeze([...definition.signedKey]) } : {}),
|
|
253
|
+
});
|
|
147
254
|
const table = (ctx) => new TableClass(ctx, frozen);
|
|
148
|
-
|
|
255
|
+
const rowId = (row) => {
|
|
256
|
+
const { name, signedBy, signedKey, schema } = frozen;
|
|
257
|
+
if (!signedBy || !signedKey) {
|
|
258
|
+
throw new Error(`Table ${name} has no signedKey, so its row ids come from Peers when rows are first saved`);
|
|
259
|
+
}
|
|
260
|
+
const identityRow = Object.fromEntries([signedBy, ...signedKey].map((field) => [
|
|
261
|
+
field,
|
|
262
|
+
schema.shape[field].parse(row[field], { path: [field] }),
|
|
263
|
+
]));
|
|
264
|
+
return (0, signed_row_id_1.signedRowIdFor)({ name, signedBy, signedKey }, identityRow);
|
|
265
|
+
};
|
|
266
|
+
return Object.freeze(Object.assign(table, { kind: "table", definition: frozen, rowId }));
|
|
149
267
|
}
|
|
@@ -655,17 +655,6 @@ export declare const groupApprovalSchema: z.ZodObject<{
|
|
|
655
655
|
signedAt?: number | undefined;
|
|
656
656
|
publicRole?: import("../data").GroupMemberRole | undefined;
|
|
657
657
|
};
|
|
658
|
-
kind: "group-approval";
|
|
659
|
-
membership: {
|
|
660
|
-
role: import("../data").GroupMemberRole;
|
|
661
|
-
signature: string;
|
|
662
|
-
userId: string;
|
|
663
|
-
groupId: string;
|
|
664
|
-
groupMemberId: string;
|
|
665
|
-
deleted?: boolean | undefined;
|
|
666
|
-
publicKey?: string | undefined;
|
|
667
|
-
signedAt?: number | undefined;
|
|
668
|
-
};
|
|
669
658
|
seed: {
|
|
670
659
|
users: {
|
|
671
660
|
name: string;
|
|
@@ -703,6 +692,17 @@ export declare const groupApprovalSchema: z.ZodObject<{
|
|
|
703
692
|
signedAt?: number | undefined;
|
|
704
693
|
}[];
|
|
705
694
|
};
|
|
695
|
+
kind: "group-approval";
|
|
696
|
+
membership: {
|
|
697
|
+
role: import("../data").GroupMemberRole;
|
|
698
|
+
signature: string;
|
|
699
|
+
userId: string;
|
|
700
|
+
groupId: string;
|
|
701
|
+
groupMemberId: string;
|
|
702
|
+
deleted?: boolean | undefined;
|
|
703
|
+
publicKey?: string | undefined;
|
|
704
|
+
signedAt?: number | undefined;
|
|
705
|
+
};
|
|
706
706
|
approver: {
|
|
707
707
|
publicKey: string;
|
|
708
708
|
userId: string;
|
|
@@ -735,17 +735,6 @@ export declare const groupApprovalSchema: z.ZodObject<{
|
|
|
735
735
|
signedAt?: number | undefined;
|
|
736
736
|
publicRole?: import("../data").GroupMemberRole | undefined;
|
|
737
737
|
};
|
|
738
|
-
kind: "group-approval";
|
|
739
|
-
membership: {
|
|
740
|
-
role: import("../data").GroupMemberRole;
|
|
741
|
-
signature: string;
|
|
742
|
-
userId: string;
|
|
743
|
-
groupId: string;
|
|
744
|
-
groupMemberId: string;
|
|
745
|
-
deleted?: boolean | undefined;
|
|
746
|
-
publicKey?: string | undefined;
|
|
747
|
-
signedAt?: number | undefined;
|
|
748
|
-
};
|
|
749
738
|
seed: {
|
|
750
739
|
users: {
|
|
751
740
|
name: string;
|
|
@@ -783,6 +772,17 @@ export declare const groupApprovalSchema: z.ZodObject<{
|
|
|
783
772
|
signedAt?: number | undefined;
|
|
784
773
|
}[];
|
|
785
774
|
};
|
|
775
|
+
kind: "group-approval";
|
|
776
|
+
membership: {
|
|
777
|
+
role: import("../data").GroupMemberRole;
|
|
778
|
+
signature: string;
|
|
779
|
+
userId: string;
|
|
780
|
+
groupId: string;
|
|
781
|
+
groupMemberId: string;
|
|
782
|
+
deleted?: boolean | undefined;
|
|
783
|
+
publicKey?: string | undefined;
|
|
784
|
+
signedAt?: number | undefined;
|
|
785
|
+
};
|
|
786
786
|
approver: {
|
|
787
787
|
publicKey: string;
|
|
788
788
|
userId: string;
|
|
@@ -1607,17 +1607,6 @@ export declare const inviteMessageSchema: z.ZodDiscriminatedUnion<"kind", [z.Zod
|
|
|
1607
1607
|
signedAt?: number | undefined;
|
|
1608
1608
|
publicRole?: import("../data").GroupMemberRole | undefined;
|
|
1609
1609
|
};
|
|
1610
|
-
kind: "group-approval";
|
|
1611
|
-
membership: {
|
|
1612
|
-
role: import("../data").GroupMemberRole;
|
|
1613
|
-
signature: string;
|
|
1614
|
-
userId: string;
|
|
1615
|
-
groupId: string;
|
|
1616
|
-
groupMemberId: string;
|
|
1617
|
-
deleted?: boolean | undefined;
|
|
1618
|
-
publicKey?: string | undefined;
|
|
1619
|
-
signedAt?: number | undefined;
|
|
1620
|
-
};
|
|
1621
1610
|
seed: {
|
|
1622
1611
|
users: {
|
|
1623
1612
|
name: string;
|
|
@@ -1655,6 +1644,17 @@ export declare const inviteMessageSchema: z.ZodDiscriminatedUnion<"kind", [z.Zod
|
|
|
1655
1644
|
signedAt?: number | undefined;
|
|
1656
1645
|
}[];
|
|
1657
1646
|
};
|
|
1647
|
+
kind: "group-approval";
|
|
1648
|
+
membership: {
|
|
1649
|
+
role: import("../data").GroupMemberRole;
|
|
1650
|
+
signature: string;
|
|
1651
|
+
userId: string;
|
|
1652
|
+
groupId: string;
|
|
1653
|
+
groupMemberId: string;
|
|
1654
|
+
deleted?: boolean | undefined;
|
|
1655
|
+
publicKey?: string | undefined;
|
|
1656
|
+
signedAt?: number | undefined;
|
|
1657
|
+
};
|
|
1658
1658
|
approver: {
|
|
1659
1659
|
publicKey: string;
|
|
1660
1660
|
userId: string;
|
|
@@ -1687,17 +1687,6 @@ export declare const inviteMessageSchema: z.ZodDiscriminatedUnion<"kind", [z.Zod
|
|
|
1687
1687
|
signedAt?: number | undefined;
|
|
1688
1688
|
publicRole?: import("../data").GroupMemberRole | undefined;
|
|
1689
1689
|
};
|
|
1690
|
-
kind: "group-approval";
|
|
1691
|
-
membership: {
|
|
1692
|
-
role: import("../data").GroupMemberRole;
|
|
1693
|
-
signature: string;
|
|
1694
|
-
userId: string;
|
|
1695
|
-
groupId: string;
|
|
1696
|
-
groupMemberId: string;
|
|
1697
|
-
deleted?: boolean | undefined;
|
|
1698
|
-
publicKey?: string | undefined;
|
|
1699
|
-
signedAt?: number | undefined;
|
|
1700
|
-
};
|
|
1701
1690
|
seed: {
|
|
1702
1691
|
users: {
|
|
1703
1692
|
name: string;
|
|
@@ -1735,6 +1724,17 @@ export declare const inviteMessageSchema: z.ZodDiscriminatedUnion<"kind", [z.Zod
|
|
|
1735
1724
|
signedAt?: number | undefined;
|
|
1736
1725
|
}[];
|
|
1737
1726
|
};
|
|
1727
|
+
kind: "group-approval";
|
|
1728
|
+
membership: {
|
|
1729
|
+
role: import("../data").GroupMemberRole;
|
|
1730
|
+
signature: string;
|
|
1731
|
+
userId: string;
|
|
1732
|
+
groupId: string;
|
|
1733
|
+
groupMemberId: string;
|
|
1734
|
+
deleted?: boolean | undefined;
|
|
1735
|
+
publicKey?: string | undefined;
|
|
1736
|
+
signedAt?: number | undefined;
|
|
1737
|
+
};
|
|
1738
1738
|
approver: {
|
|
1739
1739
|
publicKey: string;
|
|
1740
1740
|
userId: string;
|
|
@@ -113,6 +113,21 @@ export interface IIsolatedPackageTable {
|
|
|
113
113
|
* table. Storage policy, like `localOnly`: changing them needs a higher `versionNumber`.
|
|
114
114
|
*/
|
|
115
115
|
indexes?: IIsolatedTableIndex[];
|
|
116
|
+
/**
|
|
117
|
+
* The required `id` field holding each row's owner, a user id. The host derives each row's
|
|
118
|
+
* id from its owner (see `signedKey`), signs rows on save with the signed-in user's key, and
|
|
119
|
+
* adds the signature, signing time, table/context binding, and `signedIdSeed` columns. In a
|
|
120
|
+
* group it refuses a row that isn't validly signed by its owner, a Writer, under its derived
|
|
121
|
+
* id. Not on a local-only table. A table has it, and the same primary key, from its first
|
|
122
|
+
* version or never.
|
|
123
|
+
*/
|
|
124
|
+
signedBy?: string;
|
|
125
|
+
/**
|
|
126
|
+
* With `signedBy`: the fields that, with the owner, name a row; each row's id is derived from
|
|
127
|
+
* its owner and these fields. Without it, from its owner and a host-chosen seed. A table has
|
|
128
|
+
* the same `signedKey` in every version.
|
|
129
|
+
*/
|
|
130
|
+
signedKey?: string[];
|
|
116
131
|
}
|
|
117
132
|
/** One index of an isolated package table: field names in order, each ascending unless set. */
|
|
118
133
|
export interface IIsolatedTableIndex {
|
|
@@ -281,7 +281,17 @@ function validatePackageTables(manifest, strict) {
|
|
|
281
281
|
if (forbiddenIdentity) {
|
|
282
282
|
throw new Error(`${tableLabel} must not declare ${forbiddenIdentity}`);
|
|
283
283
|
}
|
|
284
|
-
assertOnlyKeys(table, [
|
|
284
|
+
assertOnlyKeys(table, [
|
|
285
|
+
"name",
|
|
286
|
+
"description",
|
|
287
|
+
"primaryKeyName",
|
|
288
|
+
"fields",
|
|
289
|
+
"versionNumber",
|
|
290
|
+
"localOnly",
|
|
291
|
+
"indexes",
|
|
292
|
+
"signedBy",
|
|
293
|
+
"signedKey",
|
|
294
|
+
], tableLabel);
|
|
285
295
|
if (typeof table.name !== "string" || table.name.trim() === "") {
|
|
286
296
|
throw new Error(`${tableLabel}.name is required`);
|
|
287
297
|
}
|
|
@@ -318,6 +328,7 @@ function validatePackageTables(manifest, strict) {
|
|
|
318
328
|
table.versionNumber = 1;
|
|
319
329
|
}
|
|
320
330
|
(0, package_table_identity_1.validateTableIndexes)(table.indexes, new Set(table.fields.map((field) => field.name)), `${tableLabel}.indexes`, table.localOnly);
|
|
331
|
+
(0, package_table_identity_1.validateSignedTable)(table, tableLabel);
|
|
321
332
|
}
|
|
322
333
|
}
|
|
323
334
|
function validateProvidedContract(contract, index, packageTables, strict) {
|
|
@@ -207,6 +207,10 @@ export interface IIsolatedPackageTableDeclaration extends IIsolatedPackageTableR
|
|
|
207
207
|
localOnly?: boolean;
|
|
208
208
|
/** Indexes; see `IIsolatedPackageTable.indexes`. */
|
|
209
209
|
indexes?: IIsolatedTableIndex[];
|
|
210
|
+
/** The field holding each row's owner; see `IIsolatedPackageTable.signedBy`. */
|
|
211
|
+
signedBy?: string;
|
|
212
|
+
/** The fields naming a row among its owner's; see `IIsolatedPackageTable.signedKey`. */
|
|
213
|
+
signedKey?: string[];
|
|
210
214
|
}
|
|
211
215
|
/**
|
|
212
216
|
* Trusted host capability for isolated-package table persistence.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createMemoryIsolatedPackageTableGateway = createMemoryIsolatedPackageTableGateway;
|
|
4
4
|
exports.createIsolatedPackageTableGateway = createIsolatedPackageTableGateway;
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
|
+
const authority_write_checks_1 = require("../data/authority-write-checks");
|
|
5
7
|
const table_container_1 = require("../data/orm/table-container");
|
|
6
8
|
const types_1 = require("../data/orm/types");
|
|
7
9
|
const package_table_identity_1 = require("../data/package-table-identity");
|
|
@@ -44,12 +46,16 @@ function validateDeclaration(declaration) {
|
|
|
44
46
|
throw new Error("Isolated table localOnly must be a boolean");
|
|
45
47
|
}
|
|
46
48
|
(0, package_table_identity_1.validateTableIndexes)(declaration.indexes, fieldNames, "Isolated table indexes", declaration.localOnly);
|
|
47
|
-
|
|
49
|
+
// A stored definition's fields already carry the host's signature columns.
|
|
50
|
+
(0, package_table_identity_1.validateSignedTable)(declaration, "Isolated table", { hostFields: true });
|
|
51
|
+
const { localOnly, signedBy, signedKey, ...rest } = declaration;
|
|
48
52
|
return {
|
|
49
53
|
...rest,
|
|
50
54
|
fields: declaration.fields.map((field) => ({ ...field })),
|
|
51
55
|
versionNumber: versionNumber(declaration),
|
|
52
56
|
...(localOnly ? { localOnly: true } : {}),
|
|
57
|
+
...(signedBy === undefined ? {} : { signedBy }),
|
|
58
|
+
...(signedKey === undefined ? {} : { signedKey: [...signedKey] }),
|
|
53
59
|
};
|
|
54
60
|
}
|
|
55
61
|
function toMetaData(rawDeclaration) {
|
|
@@ -60,11 +66,14 @@ function toMetaData(rawDeclaration) {
|
|
|
60
66
|
name: declaration.tableName,
|
|
61
67
|
description: declaration.description,
|
|
62
68
|
primaryKeyName: declaration.primaryKeyName,
|
|
63
|
-
fields
|
|
69
|
+
// A signed table stores the host's signature columns beside the package's fields.
|
|
70
|
+
fields: declaration.signedBy ? (0, package_table_identity_1.withSignedTableFields)(declaration.fields) : declaration.fields,
|
|
64
71
|
versionNumber: versionNumber(declaration),
|
|
65
72
|
// Only when set: stored definitions hash their metadata, and older ones have no such keys.
|
|
66
73
|
...(declaration.localOnly ? { localOnly: true } : {}),
|
|
67
74
|
...(declaration.indexes?.length ? { indexes: declaration.indexes } : {}),
|
|
75
|
+
...(declaration.signedBy === undefined ? {} : { signedBy: declaration.signedBy }),
|
|
76
|
+
...(declaration.signedKey === undefined ? {} : { signedKey: declaration.signedKey }),
|
|
68
77
|
};
|
|
69
78
|
}
|
|
70
79
|
function normalizedMetaData(metaData) {
|
|
@@ -92,6 +101,15 @@ function selectNewerDefinition(existing, incoming) {
|
|
|
92
101
|
if (existingVersion === incomingVersion && !sameDefinition(existing, incoming)) {
|
|
93
102
|
throw new Error(`Isolated table "${(0, package_table_identity_1.packageScopedTableName)(requiredPackageId(incoming), incoming.name)}" has different schemas at version ${incomingVersion}`);
|
|
94
103
|
}
|
|
104
|
+
if (existing.signedBy !== incoming.signedBy) {
|
|
105
|
+
throw new Error(`Isolated table "${(0, package_table_identity_1.packageScopedTableName)(requiredPackageId(incoming), incoming.name)}" is signed from its first version or never; signedBy can't change`);
|
|
106
|
+
}
|
|
107
|
+
if (!(0, lodash_1.isEqual)(existing.signedKey, incoming.signedKey)) {
|
|
108
|
+
throw new Error(`Isolated table "${(0, package_table_identity_1.packageScopedTableName)(requiredPackageId(incoming), incoming.name)}" derives row ids from its signedKey, so signedKey can't change`);
|
|
109
|
+
}
|
|
110
|
+
if (existing.signedBy && existing.primaryKeyName !== incoming.primaryKeyName) {
|
|
111
|
+
throw new Error(`Isolated table "${(0, package_table_identity_1.packageScopedTableName)(requiredPackageId(incoming), incoming.name)}" keeps its derived row ids in its primary key, so the primary key can't change`);
|
|
112
|
+
}
|
|
95
113
|
const decision = (0, table_container_1.checkVersionedUpdate)(existingVersion, incomingVersion, existing, incoming);
|
|
96
114
|
if (decision === "update") {
|
|
97
115
|
return incoming;
|
|
@@ -114,6 +132,8 @@ function declarationFromMetaData(metaData) {
|
|
|
114
132
|
versionNumber: metaData.versionNumber,
|
|
115
133
|
localOnly: metaData.localOnly,
|
|
116
134
|
...(metaData.indexes?.length ? { indexes: metaData.indexes } : {}),
|
|
135
|
+
...(metaData.signedBy === undefined ? {} : { signedBy: metaData.signedBy }),
|
|
136
|
+
...(metaData.signedKey === undefined ? {} : { signedKey: metaData.signedKey }),
|
|
117
137
|
});
|
|
118
138
|
}
|
|
119
139
|
function metaDataFromStoredDefinition(record, incoming) {
|
|
@@ -136,6 +156,9 @@ function metaDataFromStoredDefinition(record, incoming) {
|
|
|
136
156
|
}
|
|
137
157
|
function registerDeclaration(declarations, byTableId, rawDeclaration) {
|
|
138
158
|
const declaration = validateDeclaration(rawDeclaration);
|
|
159
|
+
// Package declarations leave the host columns out. Only internal reconstruction of a
|
|
160
|
+
// stored definition (declarationFromMetaData) may already include those columns.
|
|
161
|
+
(0, package_table_identity_1.validateSignedTable)(declaration, "Isolated table");
|
|
139
162
|
const key = tableKey(declaration);
|
|
140
163
|
const tableId = (0, package_table_identity_1.packageScopedTableId)(declaration.packageId, declaration.tableName);
|
|
141
164
|
const existingKey = byTableId.get(tableId);
|
|
@@ -430,9 +453,11 @@ function createIsolatedPackageTableGateway(dataContext) {
|
|
|
430
453
|
if (plan.existingRecord) {
|
|
431
454
|
await definitionsTable.save(plan.existingRecord, { restoreIfDeleted: true });
|
|
432
455
|
}
|
|
433
|
-
else {
|
|
456
|
+
else if (!plan.activeMetaData.signedBy) {
|
|
434
457
|
await definitionsTable.delete(requiredTableId(plan.activeMetaData));
|
|
435
458
|
}
|
|
459
|
+
// A signed declaration is permanent even if activation fails. Retaining an unused
|
|
460
|
+
// definition is safe; deleting it would reopen the unsigned-definition bypass.
|
|
436
461
|
}
|
|
437
462
|
catch (rollbackError) {
|
|
438
463
|
failures.push(rollbackError);
|
|
@@ -445,6 +470,9 @@ function createIsolatedPackageTableGateway(dataContext) {
|
|
|
445
470
|
}
|
|
446
471
|
for (const definition of definitions) {
|
|
447
472
|
dataContext.tableContainer.registerTableDefinition(definition, { overwrite: true });
|
|
473
|
+
// A signed table's check is keyed by its physical name; register it with the table, so
|
|
474
|
+
// the host finds it when it builds the table's data source.
|
|
475
|
+
(0, authority_write_checks_1.tableWriteCheckFor)(definition.metaData);
|
|
448
476
|
}
|
|
449
477
|
declarations.clear();
|
|
450
478
|
byTableId.clear();
|
package/dist/system-ids.d.ts
CHANGED
|
@@ -213,3 +213,5 @@ export declare const packagesContractId = "00mvdhk66tdqrj3hy0bacmj32";
|
|
|
213
213
|
* Allocated once with newid() for System Host Shell v1.
|
|
214
214
|
*/
|
|
215
215
|
export declare const hostShellContractId = "00mveexhw7ezjfghxomlo011g";
|
|
216
|
+
/** Local-only System Group Members v1; allocated once with newid(). */
|
|
217
|
+
export declare const groupMembersContractId = "00mvzfzkuf4djwjrsxq9cnaxt";
|
package/dist/system-ids.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
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.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. */
|
|
@@ -220,3 +220,5 @@ exports.packagesContractId = "00mvdhk66tdqrj3hy0bacmj32";
|
|
|
220
220
|
* Allocated once with newid() for System Host Shell v1.
|
|
221
221
|
*/
|
|
222
222
|
exports.hostShellContractId = "00mveexhw7ezjfghxomlo011g";
|
|
223
|
+
/** Local-only System Group Members v1; allocated once with newid(). */
|
|
224
|
+
exports.groupMembersContractId = "00mvzfzkuf4djwjrsxq9cnaxt";
|