@peers-app/peers-sdk 0.28.11 → 0.29.0

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 (55) hide show
  1. package/dist/contracts/contract-resolvers.js +1 -0
  2. package/dist/contracts/index.d.ts +2 -1
  3. package/dist/contracts/index.js +5 -2
  4. package/dist/contracts/remote-contract-transport.d.ts +27 -0
  5. package/dist/contracts/remote-contract-transport.js +27 -0
  6. package/dist/contracts/system/group-members-contract.d.ts +25 -0
  7. package/dist/contracts/system/group-members-contract.js +50 -0
  8. package/dist/contracts/system/network-contracts.js +1 -1
  9. package/dist/data/authority-write-checks.d.ts +58 -1
  10. package/dist/data/authority-write-checks.js +176 -1
  11. package/dist/data/group-resign.d.ts +30 -0
  12. package/dist/data/group-resign.js +74 -0
  13. package/dist/data/index.d.ts +1 -0
  14. package/dist/data/index.js +1 -0
  15. package/dist/data/orm/index.d.ts +1 -0
  16. package/dist/data/orm/index.js +1 -0
  17. package/dist/data/orm/signed-package-table.d.ts +126 -0
  18. package/dist/data/orm/signed-package-table.js +293 -0
  19. package/dist/data/orm/table-container.d.ts +22 -2
  20. package/dist/data/orm/table-container.js +49 -14
  21. package/dist/data/orm/types.d.ts +12 -0
  22. package/dist/data/package-table-identity.d.ts +48 -0
  23. package/dist/data/package-table-identity.js +151 -0
  24. package/dist/data/signed-row-id.d.ts +43 -0
  25. package/dist/data/signed-row-id.js +72 -0
  26. package/dist/define/context.d.ts +9 -0
  27. package/dist/define/manifest.js +3 -1
  28. package/dist/define/system-contracts.d.ts +99 -0
  29. package/dist/define/system-contracts.js +5 -1
  30. package/dist/define/table.d.ts +32 -0
  31. package/dist/define/table.js +120 -2
  32. package/dist/device/binary-peer-connection-v2.d.ts +2 -2
  33. package/dist/device/binary-peer-connection-v2.js +51 -13
  34. package/dist/device/tx-encoding.d.ts +22 -1
  35. package/dist/device/tx-encoding.js +63 -26
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +1 -0
  38. package/dist/invites/invite-messages.d.ts +44 -44
  39. package/dist/keys.d.ts +7 -2
  40. package/dist/keys.js +61 -12
  41. package/dist/native-codecs.d.ts +34 -0
  42. package/dist/native-codecs.js +16 -0
  43. package/dist/package-loader/isolated-artifact.d.ts +17 -0
  44. package/dist/package-loader/isolated-artifact.js +15 -2
  45. package/dist/package-loader/isolated-runtime.d.ts +10 -0
  46. package/dist/package-loader/isolated-table-gateway.js +31 -3
  47. package/dist/package-loader/package-loader.js +1 -0
  48. package/dist/serial-json.d.ts +7 -0
  49. package/dist/serial-json.js +16 -2
  50. package/dist/system-ids.d.ts +2 -0
  51. package/dist/system-ids.js +3 -1
  52. package/dist/types/peer-device.d.ts +6 -0
  53. package/dist/types/peer-device.js +7 -1
  54. package/dist/utils.js +2 -2
  55. package/package.json +1 -1
@@ -24,6 +24,18 @@ export interface ITableMetaData {
24
24
  iconClassName?: string;
25
25
  localOnly?: boolean;
26
26
  versionNumber?: number;
27
+ /**
28
+ * The `id` field naming the user who owns each row. The host signs a row with the signed-in
29
+ * user's key when it's saved, and a group refuses a row that isn't validly signed by its
30
+ * owner. Set from `defineTable({ signedBy })`; a table has it from its first version or never.
31
+ */
32
+ signedBy?: string;
33
+ /**
34
+ * In a signed table, the fields that with the owner name a row: each owner has one row per
35
+ * key, and its id is derived from the owner and the key. Without it, a row's id is derived
36
+ * from its owner and a host-chosen seed. Set from `defineTable({ signedKey })`; it can't change.
37
+ */
38
+ signedKey?: string[];
27
39
  }
28
40
  /**
29
41
  * Convert field metadata to the runtime Zod schema the Runtime validates table rows with.
@@ -1,4 +1,52 @@
1
+ import { type IField } from "../types/field-type";
1
2
  import type { ITableDefinitionRecord } from "./table-definitions-table";
3
+ /**
4
+ * The columns the host adds to a signed package table (`signedBy`): the owner's signature over
5
+ * the row, its signing time, the table/context it authorizes, and, in a table without
6
+ * `signedKey`, the seed its id was derived from. A package's schema doesn't declare them.
7
+ */
8
+ export declare const SIGNED_TABLE_FIELDS: readonly IField[];
9
+ /** The names of {@link SIGNED_TABLE_FIELDS}. */
10
+ export declare const SIGNED_TABLE_FIELD_NAMES: ReadonlySet<string>;
11
+ /** The parts of a table declaration {@link validateSignedTable} checks. */
12
+ export interface ISignedTableDeclaration {
13
+ /** The table's declared fields. */
14
+ fields: readonly IField[];
15
+ /** The primary key field. */
16
+ primaryKeyName: string;
17
+ /** The owner field, if the table is signed. */
18
+ signedBy?: unknown;
19
+ /** The key fields, if declared. */
20
+ signedKey?: unknown;
21
+ /** The table's storage policy. */
22
+ localOnly?: boolean;
23
+ }
24
+ /**
25
+ * Validate a table's `signedBy` and `signedKey` declaration against its fields:
26
+ * - `signedBy` names a required field of type `id`, and the table isn't local-only (there'd be
27
+ * nothing to verify);
28
+ * - the primary key is a single `id` field other than the owner field, since Peers derives
29
+ * every row's id from its owner;
30
+ * - `signedKey`, when set, lists distinct required scalar fields (string, id, number, boolean)
31
+ * other than the primary key and the owner field, and needs `signedBy`;
32
+ * - the schema doesn't declare the host's signature columns itself.
33
+ *
34
+ * @param table - The declaration's fields, primary key, `signedBy`, `signedKey`, and `localOnly`.
35
+ * @param label - Where the declaration comes from, for errors.
36
+ * @param options - `hostFields`: the fields already include the host's signature columns (a
37
+ * stored definition), so they aren't refused.
38
+ * @throws When any of those conditions fails.
39
+ */
40
+ export declare function validateSignedTable(table: ISignedTableDeclaration, label: string, options?: {
41
+ hostFields?: boolean;
42
+ }): void;
43
+ /**
44
+ * `fields` with the host's signature columns ({@link SIGNED_TABLE_FIELDS}) added, for a signed
45
+ * table. Columns already present are kept as they are, so a stored definition round-trips.
46
+ *
47
+ * @param fields - A signed table's declared fields.
48
+ */
49
+ export declare function withSignedTableFields(fields: readonly IField[]): IField[];
2
50
  /**
3
51
  * Validate a guest-supplied isolated-table or field identifier before it can
4
52
  * reach ORM-generated SQL.
@@ -1,13 +1,149 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SIGNED_TABLE_FIELD_NAMES = exports.SIGNED_TABLE_FIELDS = void 0;
4
+ exports.validateSignedTable = validateSignedTable;
5
+ exports.withSignedTableFields = withSignedTableFields;
3
6
  exports.validateIsolatedSqlIdentifier = validateIsolatedSqlIdentifier;
4
7
  exports.validateTableIndexes = validateTableIndexes;
5
8
  exports.validatePackageTableName = validatePackageTableName;
6
9
  exports.packageScopedTableName = packageScopedTableName;
7
10
  exports.packageScopedTableId = packageScopedTableId;
8
11
  exports.validateTableDefinitionRecord = validateTableDefinitionRecord;
12
+ const field_type_1 = require("../types/field-type");
9
13
  const utils_1 = require("../utils");
10
14
  const ISOLATED_SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
15
+ /**
16
+ * The columns the host adds to a signed package table (`signedBy`): the owner's signature over
17
+ * the row, its signing time, the table/context it authorizes, and, in a table without
18
+ * `signedKey`, the seed its id was derived from. A package's schema doesn't declare them.
19
+ */
20
+ exports.SIGNED_TABLE_FIELDS = Object.freeze([
21
+ Object.freeze({
22
+ name: "signature",
23
+ type: field_type_1.FieldType.string,
24
+ optional: true,
25
+ description: "The owner's signature over the row, written by the host.",
26
+ }),
27
+ Object.freeze({
28
+ name: "signedAt",
29
+ type: field_type_1.FieldType.number,
30
+ optional: true,
31
+ description: "When the owner signed the row, written by the host.",
32
+ }),
33
+ Object.freeze({
34
+ name: "signedContextId",
35
+ type: field_type_1.FieldType.id,
36
+ optional: true,
37
+ description: "The context this signature belongs to, written by the host.",
38
+ }),
39
+ Object.freeze({
40
+ name: "signedTableId",
41
+ type: field_type_1.FieldType.id,
42
+ optional: true,
43
+ description: "The package table this signature belongs to, written by the host.",
44
+ }),
45
+ Object.freeze({
46
+ name: "signedIdSeed",
47
+ type: field_type_1.FieldType.string,
48
+ optional: true,
49
+ description: "What the row's id was derived from, with its owner, in a table without signedKey; written by the host.",
50
+ }),
51
+ ]);
52
+ /** The names of {@link SIGNED_TABLE_FIELDS}. */
53
+ exports.SIGNED_TABLE_FIELD_NAMES = new Set(exports.SIGNED_TABLE_FIELDS.map((field) => field.name));
54
+ /** The field types a signed table's key field may have: one scalar each. */
55
+ const SIGNED_KEY_FIELD_TYPES = new Set([
56
+ field_type_1.FieldType.string,
57
+ field_type_1.FieldType.id,
58
+ field_type_1.FieldType.number,
59
+ field_type_1.FieldType.boolean,
60
+ ]);
61
+ /**
62
+ * Validate a table's `signedBy` and `signedKey` declaration against its fields:
63
+ * - `signedBy` names a required field of type `id`, and the table isn't local-only (there'd be
64
+ * nothing to verify);
65
+ * - the primary key is a single `id` field other than the owner field, since Peers derives
66
+ * every row's id from its owner;
67
+ * - `signedKey`, when set, lists distinct required scalar fields (string, id, number, boolean)
68
+ * other than the primary key and the owner field, and needs `signedBy`;
69
+ * - the schema doesn't declare the host's signature columns itself.
70
+ *
71
+ * @param table - The declaration's fields, primary key, `signedBy`, `signedKey`, and `localOnly`.
72
+ * @param label - Where the declaration comes from, for errors.
73
+ * @param options - `hostFields`: the fields already include the host's signature columns (a
74
+ * stored definition), so they aren't refused.
75
+ * @throws When any of those conditions fails.
76
+ */
77
+ function validateSignedTable(table, label, options = {}) {
78
+ const { fields, primaryKeyName, signedBy, signedKey, localOnly } = table;
79
+ if (signedBy === undefined) {
80
+ if (signedKey !== undefined)
81
+ throw new Error(`${label}.signedKey needs signedBy`);
82
+ return;
83
+ }
84
+ if (typeof signedBy !== "string" || signedBy.trim() === "") {
85
+ throw new Error(`${label}.signedBy must name a field`);
86
+ }
87
+ const field = fields.find((candidate) => candidate.name === signedBy);
88
+ if (!field) {
89
+ throw new Error(`${label}.signedBy names a field the table doesn't have: "${signedBy}"`);
90
+ }
91
+ if (field.type !== field_type_1.FieldType.id || field.isArray || field.optional) {
92
+ throw new Error(`${label}.signedBy must name a required field of type id, a user id`);
93
+ }
94
+ if (localOnly) {
95
+ throw new Error(`${label}.signedBy can't be set on a local-only table: nothing syncs`);
96
+ }
97
+ const primaryKey = fields.find((candidate) => candidate.name === primaryKeyName);
98
+ if (primaryKey && (primaryKey.type !== field_type_1.FieldType.id || primaryKey.isArray)) {
99
+ throw new Error(`${label}: a signed table's primary key must be an id field`);
100
+ }
101
+ if (primaryKeyName === signedBy) {
102
+ throw new Error(`${label}: a signed table's primary key can't be its owner field; use signedKey: [] for one row per owner`);
103
+ }
104
+ if (signedKey !== undefined) {
105
+ if (!Array.isArray(signedKey))
106
+ throw new Error(`${label}.signedKey must be a list of fields`);
107
+ const seen = new Set();
108
+ for (const name of signedKey) {
109
+ const keyField = typeof name === "string" ? fields.find((candidate) => candidate.name === name) : undefined;
110
+ if (!keyField) {
111
+ throw new Error(`${label}.signedKey names a field the table doesn't have: "${name}"`);
112
+ }
113
+ if (seen.has(name))
114
+ throw new Error(`${label}.signedKey lists "${name}" twice`);
115
+ seen.add(name);
116
+ if (name === primaryKeyName || name === signedBy || exports.SIGNED_TABLE_FIELD_NAMES.has(name)) {
117
+ throw new Error(`${label}.signedKey can't list "${name}": the owner and the id are already part of a row's identity`);
118
+ }
119
+ if (!SIGNED_KEY_FIELD_TYPES.has(keyField.type) ||
120
+ keyField.isArray ||
121
+ keyField.optional ||
122
+ keyField.defaultValue !== undefined) {
123
+ throw new Error(`${label}.signedKey field "${name}" must be a required string, id, number, or boolean`);
124
+ }
125
+ }
126
+ }
127
+ if (!options.hostFields) {
128
+ const reserved = fields.find((candidate) => exports.SIGNED_TABLE_FIELD_NAMES.has(candidate.name));
129
+ if (reserved) {
130
+ throw new Error(`${label} declares "${reserved.name}", which the host adds to a signed table itself`);
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * `fields` with the host's signature columns ({@link SIGNED_TABLE_FIELDS}) added, for a signed
136
+ * table. Columns already present are kept as they are, so a stored definition round-trips.
137
+ *
138
+ * @param fields - A signed table's declared fields.
139
+ */
140
+ function withSignedTableFields(fields) {
141
+ const names = new Set(fields.map((field) => field.name));
142
+ return [
143
+ ...fields,
144
+ ...exports.SIGNED_TABLE_FIELDS.filter((field) => !names.has(field.name)).map((field) => ({ ...field })),
145
+ ];
146
+ }
11
147
  /**
12
148
  * Validate a guest-supplied isolated-table or field identifier before it can
13
149
  * reach ORM-generated SQL.
@@ -155,4 +291,19 @@ function validateTableDefinitionRecord(record) {
155
291
  throw new Error("Missing primary key column");
156
292
  // Only what reaches SQL here: an old-style package may keep a unique index on a synced table.
157
293
  validateTableIndexes(meta.indexes, names, "Table indexes", true);
294
+ validateSignedTable(meta, "Table", { hostFields: true });
295
+ if (meta.signedBy !== undefined) {
296
+ if (!meta.packageId)
297
+ throw new Error("Only a package table can be signed");
298
+ for (const field of exports.SIGNED_TABLE_FIELDS) {
299
+ const stored = meta.fields.find((candidate) => candidate.name === field.name);
300
+ if (!stored ||
301
+ stored.type !== field.type ||
302
+ !stored.optional ||
303
+ stored.isArray ||
304
+ stored.defaultValue !== undefined) {
305
+ throw new Error(`A signed table needs the host's "${field.name}" column`);
306
+ }
307
+ }
308
+ }
158
309
  }
@@ -0,0 +1,43 @@
1
+ /** The longest seed a row without `signedKey` may carry. */
2
+ export declare const MAX_SIGNED_ID_SEED_LENGTH = 64;
3
+ /** A value a signed table's key field may hold. */
4
+ export type SignedKeyValue = string | number | boolean;
5
+ /** What derives a signed table's row ids: its name, owner field, and key fields. */
6
+ export interface ISignedRowIdentity {
7
+ /** The table's declared name (not its physical `<name>_<packageId>`). */
8
+ name: string;
9
+ /** The field naming each row's owner. */
10
+ signedBy: string;
11
+ /** The fields that, with the owner, name a row; none declared means a seed per row. */
12
+ signedKey?: readonly string[];
13
+ }
14
+ /**
15
+ * The id of a row in a signed table: a hash of the table's name, the row's owner, and the row's
16
+ * key. Every device recomputes it and refuses a row whose id doesn't match, so another member
17
+ * can't claim an owner's row id: they'd have to name that owner, and only the owner can sign.
18
+ * The hash part is 21 base-36 characters (about 108 bits), so a collision costs about 2^54
19
+ * hashes: a member who chooses part of a victim's key could take one id first on some devices
20
+ * (availability only; the row's contents stay the owner's). That's the ceiling of 25-character
21
+ * peer ids.
22
+ *
23
+ * @param tableName - The table's declared name.
24
+ * @param ownerUserId - The row's owner.
25
+ * @param key - The key fields' values in declared order, or the row's seed.
26
+ */
27
+ export declare function signedRowId(tableName: string, ownerUserId: string, key: readonly SignedKeyValue[] | string): string;
28
+ /**
29
+ * Whether `id` has the form of a {@link signedRowId}: a hint, not a proof that it was derived.
30
+ *
31
+ * @param id - A candidate row id.
32
+ */
33
+ export declare function isSignedRowId(id: unknown): boolean;
34
+ /**
35
+ * The id `row` must have in `table`: from its owner and key fields when the table declares
36
+ * `signedKey`, otherwise from its owner and `seed` (the row's `signedIdSeed`).
37
+ *
38
+ * @param table - The table's name, owner field, and key fields.
39
+ * @param row - The row; its owner and key fields are read.
40
+ * @param seed - The row's seed, for a table without `signedKey`.
41
+ * @throws When the owner, a key field, or the seed is missing or isn't a valid value.
42
+ */
43
+ export declare function signedRowIdFor(table: ISignedRowIdentity, row: Record<string, unknown>, seed?: unknown): string;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_SIGNED_ID_SEED_LENGTH = void 0;
4
+ exports.signedRowId = signedRowId;
5
+ exports.isSignedRowId = isSignedRowId;
6
+ exports.signedRowIdFor = signedRowIdFor;
7
+ /**
8
+ * Row ids of signed package tables (`defineTable({ signedBy })`), bound to each row's owner.
9
+ *
10
+ * Kept apart from `package-table-identity.ts` so package code (`define/table.ts`) can compute
11
+ * them without loading lodash.
12
+ */
13
+ const peer_id_1 = require("../peer-id");
14
+ /** Leading characters of every signed-row id, so they can't collide with other derived ids. */
15
+ const SIGNED_ROW_ID_PREFIX = "000s";
16
+ /** The longest seed a row without `signedKey` may carry. */
17
+ exports.MAX_SIGNED_ID_SEED_LENGTH = 64;
18
+ /**
19
+ * The id of a row in a signed table: a hash of the table's name, the row's owner, and the row's
20
+ * key. Every device recomputes it and refuses a row whose id doesn't match, so another member
21
+ * can't claim an owner's row id: they'd have to name that owner, and only the owner can sign.
22
+ * The hash part is 21 base-36 characters (about 108 bits), so a collision costs about 2^54
23
+ * hashes: a member who chooses part of a victim's key could take one id first on some devices
24
+ * (availability only; the row's contents stay the owner's). That's the ceiling of 25-character
25
+ * peer ids.
26
+ *
27
+ * @param tableName - The table's declared name.
28
+ * @param ownerUserId - The row's owner.
29
+ * @param key - The key fields' values in declared order, or the row's seed.
30
+ */
31
+ function signedRowId(tableName, ownerUserId, key) {
32
+ return (0, peer_id_1.deterministicPeerId)(SIGNED_ROW_ID_PREFIX, JSON.stringify(["signed-row/1", tableName, ownerUserId, key]));
33
+ }
34
+ /**
35
+ * Whether `id` has the form of a {@link signedRowId}: a hint, not a proof that it was derived.
36
+ *
37
+ * @param id - A candidate row id.
38
+ */
39
+ function isSignedRowId(id) {
40
+ return typeof id === "string" && id.length === 25 && id.startsWith(SIGNED_ROW_ID_PREFIX);
41
+ }
42
+ /**
43
+ * The id `row` must have in `table`: from its owner and key fields when the table declares
44
+ * `signedKey`, otherwise from its owner and `seed` (the row's `signedIdSeed`).
45
+ *
46
+ * @param table - The table's name, owner field, and key fields.
47
+ * @param row - The row; its owner and key fields are read.
48
+ * @param seed - The row's seed, for a table without `signedKey`.
49
+ * @throws When the owner, a key field, or the seed is missing or isn't a valid value.
50
+ */
51
+ function signedRowIdFor(table, row, seed) {
52
+ const owner = row[table.signedBy];
53
+ if (typeof owner !== "string" || owner === "") {
54
+ throw new Error(`Table ${table.name}: "${table.signedBy}" must name the row's owner`);
55
+ }
56
+ if (table.signedKey) {
57
+ const values = table.signedKey.map((field) => {
58
+ const value = row[field];
59
+ if (typeof value === "string" ||
60
+ typeof value === "boolean" ||
61
+ (typeof value === "number" && Number.isFinite(value))) {
62
+ return value;
63
+ }
64
+ throw new Error(`Table ${table.name}: key field "${field}" must have a value`);
65
+ });
66
+ return signedRowId(table.name, owner, values);
67
+ }
68
+ if (typeof seed !== "string" || seed === "" || seed.length > exports.MAX_SIGNED_ID_SEED_LENGTH) {
69
+ throw new Error(`Table ${table.name}: the row has no id seed`);
70
+ }
71
+ return signedRowId(table.name, owner, seed);
72
+ }
@@ -29,6 +29,15 @@ export interface IPackageContext {
29
29
  readonly deviceId: string;
30
30
  /** Run a tool on a contract this package consumes (or provides), as this call's caller. */
31
31
  callConsumedTool(contractId: string, version: number, toolName: string, args?: unknown, options?: IPackageProviderOptions): Promise<unknown>;
32
+ /**
33
+ * Ask for a direct connection to another device in this package's data context, before calls
34
+ * that benefit from one (a large transfer, say). Remote calls use a direct connection when one
35
+ * exists and the Peers mesh otherwise; they never dial on their own. Resolves `true` when a
36
+ * direct connection exists (at most about 15 seconds), `false` when none could be made; never
37
+ * rejects for an unreachable device. The connection may still drop later, and calls then go
38
+ * through the mesh.
39
+ */
40
+ connectToDevice(deviceId: string): Promise<boolean>;
32
41
  /** Run a tool on another device. The remote device authorizes the call. */
33
42
  callRemoteTool(contractId: string, version: number, deviceId: string, toolName: string, args?: unknown): Promise<unknown>;
34
43
  /** Subscribe to an event on a consumed or provided contract. */
@@ -504,7 +504,7 @@ function observableValueShape(name, schema) {
504
504
  return empty ? { ...shape, optional: true } : shape;
505
505
  }
506
506
  function tableManifest(table) {
507
- const { name, description, primaryKeyName, schema, versionNumber, localOnly, indexes } = table.definition;
507
+ const { name, description, primaryKeyName, schema, versionNumber, localOnly, indexes, signedBy, signedKey, } = table.definition;
508
508
  return {
509
509
  name,
510
510
  description,
@@ -512,6 +512,8 @@ function tableManifest(table) {
512
512
  fields: describing(`Table ${name}`, () => irFields(schema)),
513
513
  ...(versionNumber === undefined ? {} : { versionNumber }),
514
514
  ...(localOnly ? { localOnly: true } : {}),
515
+ ...(signedBy === undefined ? {} : { signedBy }),
516
+ ...(signedKey === undefined ? {} : { signedKey: [...signedKey] }),
515
517
  ...(indexes?.length
516
518
  ? {
517
519
  indexes: indexes.map((index) => ({
@@ -11,6 +11,105 @@ export declare const SystemHttp: import("./contract-ref").IContractRef<{
11
11
  packageId: string;
12
12
  }): Promise<import("../contracts/system/http-contract").IHttpPolicyInfo>;
13
13
  }>;
14
+ /** System Identity v1's package-safe session read. Other identity tools refuse packages. */
15
+ export declare const SystemIdentity: import("./contract-ref").IContractRef<Pick<{
16
+ startSource(input: import("..").DevicePairingStartSourceInput): Promise<import("..").DevicePairingState>;
17
+ startDestination(input?: import("..").DevicePairingStartDestinationInput): Promise<import("..").DevicePairingState>;
18
+ approve(input: import("..").DevicePairingCeremonyAction): Promise<import("..").DevicePairingState>;
19
+ reject(input: import("..").DevicePairingCeremonyAction): Promise<import("..").DevicePairingState>;
20
+ cancel(input: import("..").DevicePairingCeremonyAction): Promise<import("..").DevicePairingState>;
21
+ getSession(): Promise<import("../contracts/system/identity-contract").IIdentitySessionInfo>;
22
+ signIn(input: {
23
+ userId: string;
24
+ secretKey: string;
25
+ }): Promise<void>;
26
+ signOut(): Promise<void>;
27
+ registerWithPeersServices(): Promise<{
28
+ token: string;
29
+ }>;
30
+ getKeyInfo(): Promise<import("../contracts/system/identity-contract").IIdentityKeyInfo>;
31
+ rotateKey(input?: import("../contracts/system/identity-contract").IIdentityRotateKeyInput): Promise<import("../contracts/system/identity-contract").IIdentityRotateKeyResult>;
32
+ getRecoveryEmail(): Promise<{
33
+ email?: string;
34
+ }>;
35
+ bindEmailStart(input: {
36
+ email: string;
37
+ }): Promise<{
38
+ status: string;
39
+ }>;
40
+ bindEmailVerify(input: {
41
+ email: string;
42
+ code: string;
43
+ }): Promise<{
44
+ email: string;
45
+ }>;
46
+ unbindEmail(): Promise<{
47
+ status: string;
48
+ }>;
49
+ startAnchorSession(input?: {
50
+ userId?: string;
51
+ }): Promise<{
52
+ status: string;
53
+ }>;
54
+ confirmAnchorSession(input: {
55
+ code: string;
56
+ userId?: string;
57
+ }): Promise<{
58
+ expiresIn: number;
59
+ }>;
60
+ contestRecovery(input: {
61
+ pendingKey: string;
62
+ }): Promise<{
63
+ status: string;
64
+ }>;
65
+ acceptRecovery(input: {
66
+ userId: string;
67
+ pendingKey: string;
68
+ }): Promise<{
69
+ status: string;
70
+ }>;
71
+ recoverKey(input: {
72
+ userId: string;
73
+ publish?: "anchors" | "manual";
74
+ confirm?: boolean;
75
+ }): Promise<{
76
+ publicKey: string;
77
+ committed: boolean;
78
+ manualDocument?: import("..").IAnchorDocument;
79
+ warnings: string[];
80
+ }>;
81
+ setAnchors(input: {
82
+ anchors: import("..").IAnchorRef[];
83
+ }): Promise<{
84
+ anchors: import("..").IAnchorRef[];
85
+ }>;
86
+ passkeyRegisterStart(input: {
87
+ origin: string;
88
+ }): Promise<{
89
+ options: Record<string, unknown>;
90
+ }>;
91
+ passkeyRegisterFinish(input: {
92
+ response: Record<string, unknown>;
93
+ }): Promise<{
94
+ status: string;
95
+ }>;
96
+ passkeyAuthStart(input: {
97
+ origin: string;
98
+ userId?: string;
99
+ }): Promise<{
100
+ options: Record<string, unknown>;
101
+ }>;
102
+ passkeyAuthFinish(input: {
103
+ response: Record<string, unknown>;
104
+ userId?: string;
105
+ }): Promise<{
106
+ expiresIn: number;
107
+ }>;
108
+ }, "getSession">>;
109
+ /** Current verified members of the calling package's own data context, including Readers. */
110
+ export declare const SystemGroupMembers: import("./contract-ref").IContractRef<{
111
+ getMembers(): Promise<import("../contracts/system/group-members-contract").IGroupMembersResult>;
112
+ }>;
14
113
  /**
15
114
  * System Scheduler v1: run one of the package's own tools later, on this device. Declare it
16
115
  * with `pkg.consumes(SystemScheduler)`, optionally.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SystemContractCatalog = exports.SystemScheduler = exports.SystemHttp = void 0;
3
+ exports.SystemContractCatalog = exports.SystemScheduler = exports.SystemGroupMembers = exports.SystemIdentity = exports.SystemHttp = void 0;
4
4
  const system_ids_1 = require("../system-ids");
5
5
  const contract_ref_1 = require("./contract-ref");
6
6
  /**
@@ -8,6 +8,10 @@ const contract_ref_1 = require("./contract-ref");
8
8
  * with `pkg.consumes(SystemHttp)`.
9
9
  */
10
10
  exports.SystemHttp = (0, contract_ref_1.contractRef)(system_ids_1.httpContractId, 1);
11
+ /** System Identity v1's package-safe session read. Other identity tools refuse packages. */
12
+ exports.SystemIdentity = (0, contract_ref_1.contractRef)(system_ids_1.identityContractId, 1);
13
+ /** Current verified members of the calling package's own data context, including Readers. */
14
+ exports.SystemGroupMembers = (0, contract_ref_1.contractRef)(system_ids_1.groupMembersContractId, 1);
11
15
  /**
12
16
  * System Scheduler v1: run one of the package's own tools later, on this device. Declare it
13
17
  * with `pkg.consumes(SystemScheduler)`, optionally.
@@ -23,6 +23,28 @@ export interface IPackageTableDefinition<S extends z.AnyZodObject = z.AnyZodObje
23
23
  * schema change, so raise `versionNumber`.
24
24
  */
25
25
  indexes?: IPackageTableIndex<S>[];
26
+ /**
27
+ * Make each row its owner's: the named field, a required `zodPeerId`, holds the user id of
28
+ * the member who owns the row. Peers signs a row with the signed-in user's key when it's
29
+ * saved, refuses a save that names anyone else as owner, and in a group refuses any row
30
+ * (synced or local) that isn't validly signed by its owner, a Writer, or that was signed
31
+ * before the row on record. Peers sets each row's id from its owner (see `signedKey`), so use
32
+ * the id `save` returns. Rows aren't deleted: mark them instead. `save` refuses `weakInsert`,
33
+ * since a row counts from when its owner signs it. Can't be combined with
34
+ * `localOnly`; the primary key must be a `zodPeerId` other than the owner field; and the
35
+ * schema must leave `signature`, `signedAt`, `signedContextId`, `signedTableId`, and
36
+ * `signedIdSeed` to Peers. Signatures authorize only this table and context. A table is
37
+ * signed from its first version or not at all.
38
+ */
39
+ signedBy?: Extract<keyof z.infer<S>, string>;
40
+ /**
41
+ * With `signedBy`: the fields that, with the owner, name a row, so each owner has one row per
42
+ * key (`[]` for one row per owner). A row's id is derived from its owner and these fields:
43
+ * saving the same key again updates that row, and {@link IPackageTable.rowId} gives the id.
44
+ * Each is a required string, id, number, or boolean, and a row's key can't change. Without
45
+ * it, Peers derives a new row's id from its owner and the id you pass. Can't change later.
46
+ */
47
+ signedKey?: readonly Extract<keyof z.infer<S>, string>[];
26
48
  /**
27
49
  * The table's class, to override its methods: `Feeds(ctx)` returns one, and so does every
28
50
  * consumer call through a contract, so an override is always the logic in use. Defaults to
@@ -150,6 +172,16 @@ export interface IPackageTable<S extends z.AnyZodObject = z.AnyZodObject, N exte
150
172
  readonly definition: Readonly<IPackageTableDefinition<S>> & {
151
173
  readonly name: N;
152
174
  };
175
+ /**
176
+ * The id of a row in a table declared with `signedBy` and `signedKey`, from its owner and key
177
+ * fields: what `save` stores the row under, for `get`. Throws for any other table (a signed
178
+ * table without `signedKey` gets its ids from Peers when rows are first saved).
179
+ * Parses the owner and key inputs with their field schemas, including transforms, as `save`
180
+ * does; other fields may be omitted.
181
+ *
182
+ * @param row - The owner field and the key fields.
183
+ */
184
+ rowId(row: Partial<z.input<S>>): string;
153
185
  }
154
186
  /**
155
187
  * Declare one of the package's tables from a zod schema.