@peers-app/peers-sdk 0.27.4 → 0.28.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 (92) hide show
  1. package/dist/context/user-context.d.ts +7 -1
  2. package/dist/context/user-context.js +4 -9
  3. package/dist/contracts/contract-proxy.d.ts +5 -0
  4. package/dist/contracts/contract-proxy.js +2 -2
  5. package/dist/contracts/contract-resolvers.d.ts +2 -2
  6. package/dist/contracts/contract-resolvers.js +14 -15
  7. package/dist/contracts/contract-transport.d.ts +2 -1
  8. package/dist/contracts/contract-transport.js +24 -2
  9. package/dist/contracts/system/network-contracts.d.ts +1 -1
  10. package/dist/contracts/tool-catalog-service.js +1 -1
  11. package/dist/contracts/tool-catalog.js +6 -2
  12. package/dist/data/assistants.d.ts +3 -3
  13. package/dist/data/authority-write-checks.d.ts +42 -0
  14. package/dist/data/authority-write-checks.js +324 -0
  15. package/dist/data/change-tracking.d.ts +4 -4
  16. package/dist/data/create-group.js +1 -0
  17. package/dist/data/devices.d.ts +27 -4
  18. package/dist/data/devices.js +31 -0
  19. package/dist/data/group-authority.d.ts +111 -0
  20. package/dist/data/group-authority.js +281 -0
  21. package/dist/data/group-members.d.ts +8 -2
  22. package/dist/data/group-members.js +41 -18
  23. package/dist/data/group-permissions.d.ts +15 -31
  24. package/dist/data/group-permissions.js +25 -95
  25. package/dist/data/group-resign.d.ts +38 -0
  26. package/dist/data/group-resign.js +71 -0
  27. package/dist/data/groups.d.ts +11 -0
  28. package/dist/data/groups.js +31 -13
  29. package/dist/data/index.d.ts +3 -0
  30. package/dist/data/index.js +3 -0
  31. package/dist/data/invites.d.ts +14 -0
  32. package/dist/data/orm/index.d.ts +1 -0
  33. package/dist/data/orm/index.js +1 -0
  34. package/dist/data/orm/sql.data-source.d.ts +2 -2
  35. package/dist/data/orm/sql.data-source.js +8 -9
  36. package/dist/data/orm/table-container.js +14 -8
  37. package/dist/data/orm/write-checks.d.ts +89 -0
  38. package/dist/data/orm/write-checks.js +115 -0
  39. package/dist/data/package-table-identity.d.ts +6 -0
  40. package/dist/data/package-table-identity.js +51 -0
  41. package/dist/data/package-version-resolver.d.ts +15 -0
  42. package/dist/data/package-version-resolver.js +58 -3
  43. package/dist/data/package-versions.d.ts +20 -14
  44. package/dist/data/package-versions.js +15 -9
  45. package/dist/data/packages.d.ts +6 -1
  46. package/dist/data/packages.js +15 -20
  47. package/dist/data/persistent-vars.js +2 -39
  48. package/dist/data/sync-recovery-queue.d.ts +4 -4
  49. package/dist/data/sync-recovery-queue.js +7 -1
  50. package/dist/data/tool-access-approvals.d.ts +3 -3
  51. package/dist/data/user-permissions.d.ts +33 -2
  52. package/dist/data/user-permissions.js +87 -10
  53. package/dist/data/users.d.ts +49 -12
  54. package/dist/data/users.js +21 -1
  55. package/dist/data/workflows.d.ts +1 -1
  56. package/dist/device/binary-peer-connection-v2.d.ts +8 -16
  57. package/dist/device/binary-peer-connection-v2.js +15 -31
  58. package/dist/device/connection.d.ts +35 -44
  59. package/dist/device/connection.js +188 -186
  60. package/dist/device/device.d.ts +1 -8
  61. package/dist/device/device.js +1 -30
  62. package/dist/device/frame-cipher.d.ts +1 -1
  63. package/dist/device/frame-cipher.js +1 -1
  64. package/dist/device/get-trust-level-fn.js +3 -6
  65. package/dist/device/socket.type.d.ts +6 -12
  66. package/dist/device-pairing/types.d.ts +26 -26
  67. package/dist/identity/user-row-change.d.ts +3 -1
  68. package/dist/identity/user-row-change.js +33 -18
  69. package/dist/invites/group-approval.js +23 -24
  70. package/dist/invites/invite-messages.d.ts +250 -28
  71. package/dist/invites/invite-token.d.ts +18 -0
  72. package/dist/invites/invite-token.js +2 -0
  73. package/dist/keys.d.ts +7 -0
  74. package/dist/keys.js +27 -0
  75. package/dist/package-installer/package-installer.d.ts +1 -1
  76. package/dist/package-installer/package-installer.js +8 -3
  77. package/dist/package-installer/package-propagation.d.ts +2 -0
  78. package/dist/package-installer/package-propagation.js +20 -38
  79. package/dist/package-installer/package-remote-checker.js +15 -3
  80. package/dist/package-loader/isolated-artifact.js +0 -2
  81. package/dist/package-loader/package-loader.js +6 -0
  82. package/dist/types/peer-device.d.ts +2 -0
  83. package/dist/types/workflow.d.ts +2 -2
  84. package/package.json +1 -1
  85. package/dist/data/package-permissions.d.ts +0 -14
  86. package/dist/data/package-permissions.js +0 -26
  87. package/dist/data/package-version-permissions.d.ts +0 -14
  88. package/dist/data/package-version-permissions.js +0 -30
  89. package/dist/device/binary-peer-connection.d.ts +0 -58
  90. package/dist/device/binary-peer-connection.js +0 -516
  91. package/dist/device/streamed-socket.d.ts +0 -23
  92. package/dist/device/streamed-socket.js +0 -255
@@ -10,7 +10,7 @@ export declare const SYNC_RECOVERY_STUCK_ATTEMPTS = 5;
10
10
  /** How long a still-retrying entry must have been failing before it is stuck. */
11
11
  export declare const SYNC_RECOVERY_STUCK_AGE_MS: number;
12
12
  /** Why automatic recovery stopped asking peers for an entry. */
13
- export declare const syncRecoveryParkedReasons: readonly ["schema", "unique-conflict", "unresolvable"];
13
+ export declare const syncRecoveryParkedReasons: readonly ["schema", "unique-conflict", "unresolvable", "authorization"];
14
14
  /** Why automatic recovery stopped asking peers for an entry. */
15
15
  export type SyncRecoveryParkedReason = (typeof syncRecoveryParkedReasons)[number];
16
16
  /** One recorded materialization failure for a synchronized record. */
@@ -50,7 +50,7 @@ export declare const syncRecoveryEntrySchema: z.ZodObject<{
50
50
  }>, "many">;
51
51
  /** Set when peer retry has stopped. Absent while the entry is still retrying. */
52
52
  parkedAt: z.ZodOptional<z.ZodNumber>;
53
- parkedReason: z.ZodOptional<z.ZodEnum<["schema", "unique-conflict", "unresolvable"]>>;
53
+ parkedReason: z.ZodOptional<z.ZodEnum<["schema", "unique-conflict", "unresolvable", "authorization"]>>;
54
54
  /** Earliest time a retrying entry should ask peers again. */
55
55
  nextAttemptAt: z.ZodOptional<z.ZodNumber>;
56
56
  /**
@@ -71,7 +71,7 @@ export declare const syncRecoveryEntrySchema: z.ZodObject<{
71
71
  sourceDeviceId?: string | undefined;
72
72
  }[];
73
73
  parkedAt?: number | undefined;
74
- parkedReason?: "schema" | "unique-conflict" | "unresolvable" | undefined;
74
+ parkedReason?: "schema" | "unique-conflict" | "unresolvable" | "authorization" | undefined;
75
75
  nextAttemptAt?: number | undefined;
76
76
  sweepCount?: number | undefined;
77
77
  }, {
@@ -87,7 +87,7 @@ export declare const syncRecoveryEntrySchema: z.ZodObject<{
87
87
  sourceDeviceId?: string | undefined;
88
88
  }[];
89
89
  parkedAt?: number | undefined;
90
- parkedReason?: "schema" | "unique-conflict" | "unresolvable" | undefined;
90
+ parkedReason?: "schema" | "unique-conflict" | "unresolvable" | "authorization" | undefined;
91
91
  nextAttemptAt?: number | undefined;
92
92
  sweepCount?: number | undefined;
93
93
  }>;
@@ -20,7 +20,13 @@ exports.SYNC_RECOVERY_STUCK_ATTEMPTS = 5;
20
20
  /** How long a still-retrying entry must have been failing before it is stuck. */
21
21
  exports.SYNC_RECOVERY_STUCK_AGE_MS = 10 * 60 * 1000;
22
22
  /** Why automatic recovery stopped asking peers for an entry. */
23
- exports.syncRecoveryParkedReasons = ["schema", "unique-conflict", "unresolvable"];
23
+ exports.syncRecoveryParkedReasons = [
24
+ "schema",
25
+ "unique-conflict",
26
+ "unresolvable",
27
+ /** A write check refused the row; rechecked from local history when the group's authority changes. */
28
+ "authorization",
29
+ ];
24
30
  /** One recorded materialization failure for a synchronized record. */
25
31
  exports.syncRecoveryFailureSchema = zod_1.z.object({
26
32
  error: zod_1.z.string(),
@@ -50,8 +50,8 @@ export declare const toolAccessApprovalSchema: z.ZodObject<{
50
50
  toolName: string;
51
51
  toolId: string;
52
52
  scope: ToolAccessApprovalScope;
53
- dataContextId: string;
54
53
  createdAt: Date;
54
+ dataContextId: string;
55
55
  expiresAt: Date;
56
56
  toolAccessApprovalId: string;
57
57
  argsHash: string;
@@ -81,8 +81,8 @@ export declare const toolAccessApprovalSchema: z.ZodObject<{
81
81
  };
82
82
  status?: ToolAccessApprovalStatus | undefined;
83
83
  scope?: ToolAccessApprovalScope | undefined;
84
- assistantId?: string | undefined;
85
84
  createdAt?: Date | undefined;
85
+ assistantId?: string | undefined;
86
86
  workflowRunId?: string | undefined;
87
87
  workflowLogId?: string | undefined;
88
88
  threadMessageId?: string | undefined;
@@ -106,8 +106,8 @@ export declare function ToolAccessApprovals(dataContext?: DataContext): import("
106
106
  toolName: string;
107
107
  toolId: string;
108
108
  scope: ToolAccessApprovalScope;
109
- dataContextId: string;
110
109
  createdAt: Date;
110
+ dataContextId: string;
111
111
  expiresAt: Date;
112
112
  toolAccessApprovalId: string;
113
113
  argsHash: string;
@@ -1,12 +1,33 @@
1
1
  import type { IUser } from "./users";
2
2
  /**
3
- * Signs a user object with the provided secret key. The `anchors` list is kept on the row
4
- * but is not covered by the signature; see {@link verifyUserSignature}.
3
+ * Signs a user's profile and separately signs its initial anchor list. Later anchor changes
4
+ * are still authorized by the anchors on record; see {@link verifyUserSignature}.
5
5
  * @param user The user object to sign
6
6
  * @param secretKey The secret key to sign with
7
7
  * @returns IUser The signed user object
8
8
  */
9
9
  export declare function signUserObject(user: IUser, secretKey: string): IUser;
10
+ /** Whether the profile owner authorized this exact initial anchor list, before any anchors exist. */
11
+ export declare function hasSignedUserAnchors(user: IUser): boolean;
12
+ /**
13
+ * Whether a Users row is signed by its own `publicKey` (its anchor list is not signed): the
14
+ * only rows a group's authority takes a member's key from.
15
+ *
16
+ * @param user - A Users row.
17
+ */
18
+ export declare function isSelfSignedUser(user: IUser): boolean;
19
+ /**
20
+ * Whether two profiles or authenticated devices name the same user and both of their keys.
21
+ * This compares identity only; callers still verify signatures or the transport separately.
22
+ */
23
+ export declare function sameUserIdentity(a: Pick<IUser, "userId" | "publicKey" | "publicBoxKey">, b: Pick<IUser, "userId" | "publicKey" | "publicBoxKey">): boolean;
24
+ /**
25
+ * `source`'s anchor list with the owner's signature over it, to spread onto a profile or an
26
+ * invite identity; nothing when `source` has no list.
27
+ *
28
+ * @param source - The row or identity the list is taken from.
29
+ */
30
+ export declare function anchorFields(source: Pick<IUser, "anchors" | "anchorsSignature">): Pick<IUser, "anchors" | "anchorsSignature">;
10
31
  /**
11
32
  * Verifies that a user update signature is valid, throws on invalid signature.
12
33
  * The `anchors` list is not part of what is verified.
@@ -21,3 +42,13 @@ export declare function verifyUserSignature(user: IUser, oldUser?: IUser): void;
21
42
  * @throws Error if the signature is missing, invalid, or by another key
22
43
  */
23
44
  export declare function verifyUserSignedBySelf(user: IUser): void;
45
+ /**
46
+ * Whether `user`'s current key is `earlierKey`, or was handed over from it: `earlierKey` is in
47
+ * `keySuccession` and each link from there on is signed by its key and names the next (the
48
+ * last names `publicKey`). A forged profile can't produce this, since only the holder of
49
+ * `earlierKey` can sign its handover. The list itself sits under the profile's own signature.
50
+ *
51
+ * @param user - A profile row whose own signature has been checked.
52
+ * @param earlierKey - The key a grant or record names.
53
+ */
54
+ export declare function keySucceeds(user: IUser, earlierKey: string): boolean;
@@ -1,11 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.signUserObject = signUserObject;
4
+ exports.hasSignedUserAnchors = hasSignedUserAnchors;
5
+ exports.isSelfSignedUser = isSelfSignedUser;
6
+ exports.sameUserIdentity = sameUserIdentity;
7
+ exports.anchorFields = anchorFields;
4
8
  exports.verifyUserSignature = verifyUserSignature;
5
9
  exports.verifyUserSignedBySelf = verifyUserSignedBySelf;
10
+ exports.keySucceeds = keySucceeds;
11
+ const anchor_document_1 = require("../identity/anchor-document");
6
12
  const keys_1 = require("../keys");
7
13
  /**
8
- * The part of a `Users` row the owner signs: everything but `anchors`.
14
+ * The profile the owner signs: everything but the separately authorized anchor list.
9
15
  *
10
16
  * The anchor list on record is decided by the anchors themselves (the on-record rule), not
11
17
  * by whoever wrote the row. A peer that confirms a key change stores the row with the list
@@ -13,19 +19,68 @@ const keys_1 = require("../keys");
13
19
  * must still verify, so the list is carried beside the signature rather than under it.
14
20
  */
15
21
  function signedPart(user) {
16
- const { anchors: _anchors, ...rest } = user;
22
+ const { anchors: _anchors, anchorsSignature: _anchorsSignature, ...rest } = user;
17
23
  return rest;
18
24
  }
19
25
  /**
20
- * Signs a user object with the provided secret key. The `anchors` list is kept on the row
21
- * but is not covered by the signature; see {@link verifyUserSignature}.
26
+ * Signs a user's profile and separately signs its initial anchor list. Later anchor changes
27
+ * are still authorized by the anchors on record; see {@link verifyUserSignature}.
22
28
  * @param user The user object to sign
23
29
  * @param secretKey The secret key to sign with
24
30
  * @returns IUser The signed user object
25
31
  */
26
32
  function signUserObject(user, secretKey) {
27
33
  const signed = (0, keys_1.addSignatureToObject)(signedPart(user), secretKey);
28
- return user.anchors ? { ...signed, anchors: user.anchors } : signed;
34
+ return user.anchors
35
+ ? {
36
+ ...signed,
37
+ anchors: user.anchors,
38
+ anchorsSignature: (0, keys_1.addSignatureToObject)(anchorStatement(user), secretKey).signature,
39
+ }
40
+ : signed;
41
+ }
42
+ function anchorStatement(user) {
43
+ return {
44
+ purpose: "peers-user-anchors",
45
+ userId: user.userId,
46
+ publicKey: user.publicKey,
47
+ anchors: user.anchors ?? [],
48
+ };
49
+ }
50
+ /** Whether the profile owner authorized this exact initial anchor list, before any anchors exist. */
51
+ function hasSignedUserAnchors(user) {
52
+ const statement = { ...anchorStatement(user), signature: user.anchorsSignature };
53
+ return !!user.publicKey && (0, keys_1.signedByKey)(statement) === user.publicKey;
54
+ }
55
+ /**
56
+ * Whether a Users row is signed by its own `publicKey` (its anchor list is not signed): the
57
+ * only rows a group's authority takes a member's key from.
58
+ *
59
+ * @param user - A Users row.
60
+ */
61
+ function isSelfSignedUser(user) {
62
+ return !!user.publicKey && (0, keys_1.signedByKey)(signedPart(user)) === user.publicKey;
63
+ }
64
+ /**
65
+ * Whether two profiles or authenticated devices name the same user and both of their keys.
66
+ * This compares identity only; callers still verify signatures or the transport separately.
67
+ */
68
+ function sameUserIdentity(a, b) {
69
+ return a.userId === b.userId && a.publicKey === b.publicKey && a.publicBoxKey === b.publicBoxKey;
70
+ }
71
+ /**
72
+ * `source`'s anchor list with the owner's signature over it, to spread onto a profile or an
73
+ * invite identity; nothing when `source` has no list.
74
+ *
75
+ * @param source - The row or identity the list is taken from.
76
+ */
77
+ function anchorFields(source) {
78
+ if (!source.anchors?.length)
79
+ return {};
80
+ return {
81
+ anchors: source.anchors,
82
+ ...(source.anchorsSignature ? { anchorsSignature: source.anchorsSignature } : {}),
83
+ };
29
84
  }
30
85
  /**
31
86
  * Verifies that a user update signature is valid, throws on invalid signature.
@@ -69,9 +124,31 @@ function verifyUserSignedBySelf(user) {
69
124
  if (!user.signature) {
70
125
  throw new Error("A confirmed key change still has to be signed by the new key");
71
126
  }
72
- (0, keys_1.verifyObjectSignature)(signedPart(user));
73
- const signerPublicKey = (0, keys_1.getPublicKeyFromObjectSignature)(user) ?? "";
74
- if (signerPublicKey !== user.publicKey) {
75
- throw new Error("User signature must be signed with their own public key");
76
- }
127
+ verifyUserSignature(user);
128
+ }
129
+ /**
130
+ * Whether `user`'s current key is `earlierKey`, or was handed over from it: `earlierKey` is in
131
+ * `keySuccession` and each link from there on is signed by its key and names the next (the
132
+ * last names `publicKey`). A forged profile can't produce this, since only the holder of
133
+ * `earlierKey` can sign its handover. The list itself sits under the profile's own signature.
134
+ *
135
+ * @param user - A profile row whose own signature has been checked.
136
+ * @param earlierKey - The key a grant or record names.
137
+ */
138
+ function keySucceeds(user, earlierKey) {
139
+ if (user.publicKey === earlierKey)
140
+ return true;
141
+ const links = user.keySuccession ?? [];
142
+ const start = links.findIndex((link) => link.publicKey === earlierKey);
143
+ if (start < 0)
144
+ return false;
145
+ return links.slice(start).every((link, i, rest) => (0, anchor_document_1.verifySuccession)({
146
+ userId: user.userId,
147
+ recordPublicKey: link.publicKey,
148
+ entry: {
149
+ publicKey: rest[i + 1]?.publicKey ?? user.publicKey,
150
+ issuedAt: link.issuedAt,
151
+ authorizedBy: { publicKey: link.publicKey, signature: link.signature },
152
+ },
153
+ }));
77
154
  }
@@ -1,7 +1,29 @@
1
1
  import { z } from "zod";
2
2
  import type { DataContext } from "../context/data-context";
3
+ import type { UserRowChangeDecision } from "../identity/user-row-change";
3
4
  import type { ISaveOptions } from "./orm/data-query";
4
5
  import { Table } from "./orm/table";
6
+ /** Most earlier keys a profile carries; a rotation past this drops the oldest. */
7
+ export declare const MAX_KEY_SUCCESSION = 8;
8
+ /**
9
+ * One earlier key and its handover: `signature` is that key's signature over the
10
+ * `peers-key-succession` statement naming the next key (see `signSuccession`).
11
+ */
12
+ export declare const keySuccessionLinkSchema: z.ZodObject<{
13
+ publicKey: z.ZodString;
14
+ issuedAt: z.ZodString;
15
+ signature: z.ZodString;
16
+ }, "strip", z.ZodTypeAny, {
17
+ publicKey: string;
18
+ signature: string;
19
+ issuedAt: string;
20
+ }, {
21
+ publicKey: string;
22
+ signature: string;
23
+ issuedAt: string;
24
+ }>;
25
+ /** One earlier key and its signed handover to the next. */
26
+ export type IKeySuccessionLink = z.infer<typeof keySuccessionLinkSchema>;
5
27
  /** Schema for a signed user profile. */
6
28
  export declare const userSchema: z.ZodObject<{
7
29
  userId: z.ZodEffects<z.ZodString, string, string>;
@@ -18,6 +40,20 @@ export declare const userSchema: z.ZodObject<{
18
40
  type: "peers-services" | "https";
19
41
  url: string;
20
42
  }>, "many">>;
43
+ anchorsSignature: z.ZodOptional<z.ZodString>;
44
+ keySuccession: z.ZodOptional<z.ZodArray<z.ZodObject<{
45
+ publicKey: z.ZodString;
46
+ issuedAt: z.ZodString;
47
+ signature: z.ZodString;
48
+ }, "strip", z.ZodTypeAny, {
49
+ publicKey: string;
50
+ signature: string;
51
+ issuedAt: string;
52
+ }, {
53
+ publicKey: string;
54
+ signature: string;
55
+ issuedAt: string;
56
+ }>, "many">>;
21
57
  signature: z.ZodOptional<z.ZodString>;
22
58
  }, "strip", z.ZodTypeAny, {
23
59
  name: string;
@@ -29,6 +65,12 @@ export declare const userSchema: z.ZodObject<{
29
65
  type: "peers-services" | "https";
30
66
  url: string;
31
67
  }[] | undefined;
68
+ anchorsSignature?: string | undefined;
69
+ keySuccession?: {
70
+ publicKey: string;
71
+ signature: string;
72
+ issuedAt: string;
73
+ }[] | undefined;
32
74
  }, {
33
75
  name: string;
34
76
  publicKey: string;
@@ -39,6 +81,12 @@ export declare const userSchema: z.ZodObject<{
39
81
  type: "peers-services" | "https";
40
82
  url: string;
41
83
  }[] | undefined;
84
+ anchorsSignature?: string | undefined;
85
+ keySuccession?: {
86
+ publicKey: string;
87
+ signature: string;
88
+ issuedAt: string;
89
+ }[] | undefined;
42
90
  }>;
43
91
  /** A signed user profile shared across personal and group contexts. */
44
92
  export type IUser = z.infer<typeof userSchema>;
@@ -47,24 +95,13 @@ export type IUser = z.infer<typeof userSchema>;
47
95
  * which would otherwise call the resolver again.
48
96
  */
49
97
  export declare function writeResolvedUserKey(dataContext: DataContext, user: IUser): Promise<IUser>;
50
- /** Outcome of a {@link UserRowChangeGuard}. See `resolveUserRowChange` in the identity module. */
51
- export type UserRowChangeVerdict = {
52
- action: "apply";
53
- row: IUser;
54
- } | {
55
- action: "defer";
56
- reason: string;
57
- } | {
58
- action: "refuse";
59
- reason: string;
60
- };
61
98
  /**
62
99
  * Consulted by {@link UsersTable.save} when another user's row already exists in the table.
63
100
  * Decides whether a different key or anchor list may be stored, against the anchors on
64
101
  * record. `apply` carries the row to store, whose `anchors` may have been replaced by the
65
102
  * list on record.
66
103
  */
67
- export type UserRowChangeGuard = (personalContext: DataContext, incoming: IUser, existing: IUser) => Promise<UserRowChangeVerdict>;
104
+ export type UserRowChangeGuard = (personalContext: DataContext, incoming: IUser, existing: IUser) => Promise<UserRowChangeDecision>;
68
105
  /** Installs the identity check used by {@link UsersTable.save}. The identity module sets this. */
69
106
  export declare function setUserRowChangeGuard(guard: UserRowChangeGuard | undefined): void;
70
107
  /** User table with owner-signature enforcement outside the personal context. */
@@ -34,7 +34,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
34
34
  done = true;
35
35
  };
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.UsersTable = exports.userSchema = void 0;
37
+ exports.UsersTable = exports.userSchema = exports.keySuccessionLinkSchema = exports.MAX_KEY_SUCCESSION = void 0;
38
38
  exports.writeResolvedUserKey = writeResolvedUserKey;
39
39
  exports.setUserRowChangeGuard = setUserRowChangeGuard;
40
40
  exports.Users = Users;
@@ -50,6 +50,17 @@ const table_1 = require("./orm/table");
50
50
  const table_definitions_system_1 = require("./orm/table-definitions.system");
51
51
  const types_1 = require("./orm/types");
52
52
  const user_permissions_1 = require("./user-permissions");
53
+ /** Most earlier keys a profile carries; a rotation past this drops the oldest. */
54
+ exports.MAX_KEY_SUCCESSION = 8;
55
+ /**
56
+ * One earlier key and its handover: `signature` is that key's signature over the
57
+ * `peers-key-succession` statement naming the next key (see `signSuccession`).
58
+ */
59
+ exports.keySuccessionLinkSchema = zod_1.z.object({
60
+ publicKey: zod_1.z.string(),
61
+ issuedAt: zod_1.z.string(),
62
+ signature: zod_1.z.string(),
63
+ });
53
64
  /** Schema for a signed user profile. */
54
65
  exports.userSchema = zod_1.z.object({
55
66
  userId: zod_types_1.zodPeerId,
@@ -62,6 +73,15 @@ exports.userSchema = zod_1.z.object({
62
73
  .array(anchor_document_1.anchorRefSchema)
63
74
  .optional()
64
75
  .describe("Anchors on record for this user. A peer that already has a list updates it from those anchors, not from a row that arrives with a new key. Not covered by the row's signature"),
76
+ anchorsSignature: zod_1.z
77
+ .string()
78
+ .optional()
79
+ .describe("Owner's signature authorizing the first anchor list"),
80
+ keySuccession: zod_1.z
81
+ .array(exports.keySuccessionLinkSchema)
82
+ .max(exports.MAX_KEY_SUCCESSION)
83
+ .optional()
84
+ .describe("This user's earlier signing keys, oldest first, each with its signature handing over to the next key (the last to publicKey). A group membership granted to an earlier key still counts for the current one"),
65
85
  signature: zod_1.z
66
86
  .string()
67
87
  .optional()
@@ -3,6 +3,7 @@ export declare function Workflows(dataContext?: DataContext): import("..").Table
3
3
  name: string;
4
4
  description: string;
5
5
  updatedAt: Date;
6
+ createdBy: string;
6
7
  createdAt: Date;
7
8
  workflowId: string;
8
9
  defaultAssistantId: string;
@@ -12,6 +13,5 @@ export declare function Workflows(dataContext?: DataContext): import("..").Table
12
13
  directCallToolId?: string | undefined;
13
14
  subWorkflowId?: string | undefined;
14
15
  }[];
15
- createdBy: string;
16
16
  packageId?: string | undefined;
17
17
  }>;
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * binary-peer-connection-v2.ts
3
3
  *
4
- * Unified binary transport layer that replaces both binary-peer-connection.ts
5
- * and streamed-socket.ts. Provides two cleanly separated modes:
4
+ * Binary transport layer under every device connection. Provides two cleanly
5
+ * separated modes:
6
6
  *
7
7
  * 1. **RPC mode** (emit/on): request/response interactions with automatic
8
8
  * encoding (txEncode for objects, passthrough for Uint8Array) and transparent
9
9
  * chunking for large payloads.
10
10
  *
11
11
  * 2. **Stream mode** (sendRawBytes/onRawBytes): continuous byte transfer for
12
- * file syncing, database downloads, log streaming, etc. Each sendRawBytes
12
+ * file syncing, log streaming, etc. Each sendRawBytes
13
13
  * call = exactly one onRawBytes callback (atomic delivery after reassembly).
14
14
  *
15
15
  * Both modes share a single sendFrame() function that handles backpressure
@@ -18,7 +18,7 @@
18
18
  * 3. **Frame cipher**: once `armFrameCipher` is called (by `Connection` after
19
19
  * the handshake), every outbound frame is sealed as `FRAME_ENC` and every
20
20
  * inbound frame must be sealed. See `frame-cipher.ts` and
21
- * `working/transport-security.md`.
21
+ * `working/done/transport-security.md`.
22
22
  */
23
23
  import { Connection } from "./connection";
24
24
  import type { Device } from "./device";
@@ -61,19 +61,12 @@ export declare const DEFAULT_BINARY_PEER_RECEIVE_LIMITS: Readonly<BinaryPeerRece
61
61
  export interface WrapBinaryPeerOptions {
62
62
  /** Protocol identifier used for server address (e.g., 'wrtc' or 'ws') */
63
63
  protocol: "wrtc" | "ws";
64
- /**
65
- * Mark the transport as already secure (encrypted at transport layer).
66
- * When true, sets secureLocal and secureRemote to skip the legacy per-message
67
- * envelope against a legacy peer. Irrelevant once the frame cipher is armed.
68
- * @deprecated Removed with the legacy path.
69
- */
70
- markTransportSecure?: boolean;
71
64
  /** Optional hard limits for untrusted inbound messages. */
72
65
  receiveLimits?: Partial<BinaryPeerReceiveLimits>;
73
66
  }
74
67
  /**
75
68
  * Creates an ISocket from a binary peer. This is the core v2 factory function.
76
- * Replaces both createBinaryPeerSocket (v1) and StreamedSocket.
69
+ * Used for every device connection.
77
70
  */
78
71
  export declare function createBinaryPeerSocket(connectionId: string, peer: IBinaryPeer, protocol?: string, receiveLimitOverrides?: Partial<BinaryPeerReceiveLimits>): ISocket;
79
72
  /**
@@ -82,10 +75,9 @@ export declare function createBinaryPeerSocket(connectionId: string, peer: IBina
82
75
  */
83
76
  export declare function wrapBinaryPeer(connectionId: string, peer: IBinaryPeer, localDevice: Device, initiator: boolean, options: WrapBinaryPeerOptions, getTrustLevel?: ITrustLevelFn): Connection;
84
77
  /**
85
- * Wraps a WebRTC peer into a Connection.
86
- * WebRTC is encrypted at the transport layer (DTLS-SRTP); the frame cipher is
87
- * armed on top of it by the handshake so no code path depends on transport
88
- * classification.
78
+ * Wraps a WebRTC peer into a Connection. WebRTC is encrypted at the transport
79
+ * layer (DTLS-SRTP); the handshake arms the frame cipher on top of it, as on
80
+ * every transport.
89
81
  */
90
82
  export declare function wrapWrtc(connectionId: string, peer: IWebRTCPeer, localDevice: Device, initiator: boolean, getTrustLevel?: ITrustLevelFn, receiveLimits?: Partial<BinaryPeerReceiveLimits>): Connection;
91
83
  export {};
@@ -2,15 +2,15 @@
2
2
  /**
3
3
  * binary-peer-connection-v2.ts
4
4
  *
5
- * Unified binary transport layer that replaces both binary-peer-connection.ts
6
- * and streamed-socket.ts. Provides two cleanly separated modes:
5
+ * Binary transport layer under every device connection. Provides two cleanly
6
+ * separated modes:
7
7
  *
8
8
  * 1. **RPC mode** (emit/on): request/response interactions with automatic
9
9
  * encoding (txEncode for objects, passthrough for Uint8Array) and transparent
10
10
  * chunking for large payloads.
11
11
  *
12
12
  * 2. **Stream mode** (sendRawBytes/onRawBytes): continuous byte transfer for
13
- * file syncing, database downloads, log streaming, etc. Each sendRawBytes
13
+ * file syncing, log streaming, etc. Each sendRawBytes
14
14
  * call = exactly one onRawBytes callback (atomic delivery after reassembly).
15
15
  *
16
16
  * Both modes share a single sendFrame() function that handles backpressure
@@ -19,7 +19,7 @@
19
19
  * 3. **Frame cipher**: once `armFrameCipher` is called (by `Connection` after
20
20
  * the handshake), every outbound frame is sealed as `FRAME_ENC` and every
21
21
  * inbound frame must be sealed. See `frame-cipher.ts` and
22
- * `working/transport-security.md`.
22
+ * `working/done/transport-security.md`.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.DEFAULT_BINARY_PEER_RECEIVE_LIMITS = void 0;
@@ -240,7 +240,7 @@ function buildStreamCont(sidBytes, chunkData) {
240
240
  }
241
241
  /**
242
242
  * Creates an ISocket from a binary peer. This is the core v2 factory function.
243
- * Replaces both createBinaryPeerSocket (v1) and StreamedSocket.
243
+ * Used for every device connection.
244
244
  */
245
245
  function createBinaryPeerSocket(connectionId, peer, protocol = "binary", receiveLimitOverrides = {}) {
246
246
  const handlers = {};
@@ -265,7 +265,7 @@ function createBinaryPeerSocket(connectionId, peer, protocol = "binary", receive
265
265
  let sendSealer = null;
266
266
  let receiveOpener = null;
267
267
  // Bare sockets (no Connection) deliver plaintext streams; Connection turns
268
- // this off and re-enables it only for a verified legacy peer.
268
+ // this off, so it receives only sealed stream frames.
269
269
  let plaintextStreamsAllowed = true;
270
270
  // Every inner frame must leave room for the cipher's 17 bytes so a sealed
271
271
  // frame never exceeds the transport limit (64 KB SCTP on WebRTC). Reserved
@@ -503,7 +503,7 @@ function createBinaryPeerSocket(connectionId, peer, protocol = "binary", receive
503
503
  else
504
504
  responseMessage.result = result;
505
505
  const encoded = encodeMessage(responseMessage);
506
- sendRPC(encoded, sendOptions);
506
+ return sendRPC(encoded, sendOptions);
507
507
  };
508
508
  handler(message.args, callback);
509
509
  }
@@ -730,17 +730,8 @@ function createBinaryPeerSocket(connectionId, peer, protocol = "binary", receive
730
730
  break;
731
731
  }
732
732
  default: {
733
- // v1 backwards compatibility: if frame type isn't recognized but looks
734
- // like a v1 PROTOCOL_RPC (0x00) it's already handled above. For true
735
- // legacy format (no discriminator), try to decode as RPC.
736
- // This handles the transition period where v1 peers send raw RPC without
737
- // a frame type byte.
738
- if (bytes.length > receiveLimits.maxRpcMessageBytes) {
739
- closeForProtocolViolation("legacy RPC exceeds the message-size limit");
740
- return;
741
- }
742
- handleIncomingRPC(bytes);
743
- break;
733
+ closeForProtocolViolation(`unknown frame type ${frameType}`);
734
+ return;
744
735
  }
745
736
  }
746
737
  }
@@ -762,7 +753,6 @@ function createBinaryPeerSocket(connectionId, peer, protocol = "binary", receive
762
753
  const socket = {
763
754
  id: connectionId,
764
755
  connected: true,
765
- handlesOwnEncoding: true,
766
756
  transportType,
767
757
  stats,
768
758
  armFrameCipher,
@@ -811,26 +801,20 @@ function createBinaryPeerSocket(connectionId, peer, protocol = "binary", receive
811
801
  * This is the main implementation that handles all binary protocols.
812
802
  */
813
803
  function wrapBinaryPeer(connectionId, peer, localDevice, initiator, options, getTrustLevel) {
814
- const { protocol, markTransportSecure, receiveLimits } = options;
804
+ const { protocol, receiveLimits } = options;
815
805
  const socket = createBinaryPeerSocket(connectionId, peer, protocol, receiveLimits);
816
806
  const serverAddress = `${protocol}://${connectionId}`;
817
807
  const localServerAddresses = initiator ? undefined : [serverAddress];
818
808
  if (process.env.NODE_ENV !== "test") {
819
809
  getTrustLevel ??= (0, get_trust_level_fn_1.getTrustLevelFn)(localDevice, serverAddress);
820
810
  }
821
- const connection = new connection_1.Connection(socket, localDevice, localServerAddresses, getTrustLevel);
822
- if (markTransportSecure) {
823
- connection.secureLocal = true;
824
- connection.secureRemote = true;
825
- }
826
- return connection;
811
+ return new connection_1.Connection(socket, localDevice, localServerAddresses, getTrustLevel);
827
812
  }
828
813
  /**
829
- * Wraps a WebRTC peer into a Connection.
830
- * WebRTC is encrypted at the transport layer (DTLS-SRTP); the frame cipher is
831
- * armed on top of it by the handshake so no code path depends on transport
832
- * classification.
814
+ * Wraps a WebRTC peer into a Connection. WebRTC is encrypted at the transport
815
+ * layer (DTLS-SRTP); the handshake arms the frame cipher on top of it, as on
816
+ * every transport.
833
817
  */
834
818
  function wrapWrtc(connectionId, peer, localDevice, initiator, getTrustLevel, receiveLimits) {
835
- return wrapBinaryPeer(connectionId, peer, localDevice, initiator, { protocol: "wrtc", markTransportSecure: true, receiveLimits }, getTrustLevel);
819
+ return wrapBinaryPeer(connectionId, peer, localDevice, initiator, { protocol: "wrtc", receiveLimits }, getTrustLevel);
836
820
  }