@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.
Files changed (35) hide show
  1. package/dist/contracts/contract-resolvers.js +1 -0
  2. package/dist/contracts/index.d.ts +1 -0
  3. package/dist/contracts/index.js +1 -0
  4. package/dist/contracts/system/group-members-contract.d.ts +25 -0
  5. package/dist/contracts/system/group-members-contract.js +50 -0
  6. package/dist/data/authority-write-checks.d.ts +58 -1
  7. package/dist/data/authority-write-checks.js +176 -1
  8. package/dist/data/group-resign.d.ts +30 -0
  9. package/dist/data/group-resign.js +74 -0
  10. package/dist/data/index.d.ts +1 -0
  11. package/dist/data/index.js +1 -0
  12. package/dist/data/orm/index.d.ts +1 -0
  13. package/dist/data/orm/index.js +1 -0
  14. package/dist/data/orm/signed-package-table.d.ts +126 -0
  15. package/dist/data/orm/signed-package-table.js +293 -0
  16. package/dist/data/orm/table-container.d.ts +22 -2
  17. package/dist/data/orm/table-container.js +49 -14
  18. package/dist/data/orm/types.d.ts +12 -0
  19. package/dist/data/package-table-identity.d.ts +48 -0
  20. package/dist/data/package-table-identity.js +151 -0
  21. package/dist/data/signed-row-id.d.ts +43 -0
  22. package/dist/data/signed-row-id.js +72 -0
  23. package/dist/define/manifest.js +3 -1
  24. package/dist/define/system-contracts.d.ts +99 -0
  25. package/dist/define/system-contracts.js +5 -1
  26. package/dist/define/table.d.ts +32 -0
  27. package/dist/define/table.js +120 -2
  28. package/dist/invites/invite-messages.d.ts +44 -44
  29. package/dist/package-loader/isolated-artifact.d.ts +15 -0
  30. package/dist/package-loader/isolated-artifact.js +12 -1
  31. package/dist/package-loader/isolated-runtime.d.ts +4 -0
  32. package/dist/package-loader/isolated-table-gateway.js +31 -3
  33. package/dist/system-ids.d.ts +2 -0
  34. package/dist/system-ids.js +3 -1
  35. package/package.json +1 -1
@@ -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({ ...definition });
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
- return Object.freeze(Object.assign(table, { kind: "table", definition: frozen }));
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, ["name", "description", "primaryKeyName", "fields", "versionNumber", "localOnly", "indexes"], tableLabel);
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
- const { localOnly, ...rest } = declaration;
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: declaration.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();
@@ -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";
@@ -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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.28.10",
3
+ "version": "0.28.12",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"