@peers-app/peers-sdk 0.23.14 → 0.24.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 (80) hide show
  1. package/dist/contracts/index.d.ts +1 -0
  2. package/dist/contracts/index.js +4 -1
  3. package/dist/contracts/system/index.d.ts +2 -0
  4. package/dist/contracts/system/index.js +5 -1
  5. package/dist/contracts/system/invites-contract.d.ts +121 -0
  6. package/dist/contracts/system/invites-contract.js +150 -0
  7. package/dist/data/create-group.d.ts +24 -0
  8. package/dist/data/create-group.js +61 -0
  9. package/dist/data/group-secret.d.ts +10 -0
  10. package/dist/data/group-secret.js +26 -0
  11. package/dist/data/group-share.d.ts +0 -20
  12. package/dist/data/group-share.js +0 -35
  13. package/dist/data/index.d.ts +2 -0
  14. package/dist/data/index.js +2 -0
  15. package/dist/data/invites.d.ts +350 -0
  16. package/dist/data/invites.js +99 -0
  17. package/dist/data/users.js +4 -0
  18. package/dist/device-pairing/constants.d.ts +27 -9
  19. package/dist/device-pairing/constants.js +28 -10
  20. package/dist/device-pairing/cpace.d.ts +46 -0
  21. package/dist/device-pairing/cpace.js +173 -0
  22. package/dist/device-pairing/cpace.test.js +116 -0
  23. package/dist/device-pairing/crypto.d.ts +40 -15
  24. package/dist/device-pairing/crypto.js +74 -33
  25. package/dist/device-pairing/device-pairing.test.js +156 -119
  26. package/dist/device-pairing/index.d.ts +3 -1
  27. package/dist/device-pairing/index.js +3 -1
  28. package/dist/device-pairing/pairing-code.d.ts +27 -0
  29. package/dist/device-pairing/pairing-code.js +84 -0
  30. package/dist/device-pairing/pgp-word-list.d.ts +14 -0
  31. package/dist/device-pairing/pgp-word-list.js +531 -0
  32. package/dist/device-pairing/signaling.d.ts +17 -6
  33. package/dist/device-pairing/signaling.js +31 -8
  34. package/dist/device-pairing/transcript.d.ts +3 -3
  35. package/dist/device-pairing/transcript.js +6 -13
  36. package/dist/device-pairing/types.d.ts +870 -224
  37. package/dist/device-pairing/types.js +186 -108
  38. package/dist/index.d.ts +1 -2
  39. package/dist/index.js +1 -2
  40. package/dist/invites/data-box-schema.d.ts +15 -0
  41. package/dist/invites/data-box-schema.js +15 -0
  42. package/dist/invites/group-approval.d.ts +43 -0
  43. package/dist/invites/group-approval.js +155 -0
  44. package/dist/invites/group-approval.test.js +221 -0
  45. package/dist/invites/index.d.ts +5 -0
  46. package/dist/{group-invite → invites}/index.js +5 -3
  47. package/dist/invites/invite-epoch.d.ts +18 -0
  48. package/dist/invites/invite-epoch.js +35 -0
  49. package/dist/invites/invite-messages.d.ts +1354 -0
  50. package/dist/invites/invite-messages.js +145 -0
  51. package/dist/invites/invite-token.d.ts +334 -0
  52. package/dist/invites/invite-token.js +178 -0
  53. package/dist/invites/invite-token.test.d.ts +1 -0
  54. package/dist/invites/invite-token.test.js +123 -0
  55. package/dist/rpc-types.d.ts +5 -4
  56. package/dist/rpc-types.js +2 -1
  57. package/dist/system-ids.d.ts +22 -0
  58. package/dist/system-ids.js +23 -1
  59. package/package.json +1 -1
  60. package/dist/device-pairing/invitation.d.ts +0 -13
  61. package/dist/device-pairing/invitation.js +0 -85
  62. package/dist/group-invite/group-invite.d.ts +0 -53
  63. package/dist/group-invite/group-invite.js +0 -231
  64. package/dist/group-invite/group-invite.pvars.d.ts +0 -94
  65. package/dist/group-invite/group-invite.pvars.js +0 -139
  66. package/dist/group-invite/group-invite.types.d.ts +0 -124
  67. package/dist/group-invite/group-invite.types.js +0 -8
  68. package/dist/group-invite/index.d.ts +0 -3
  69. package/dist/user-connect/connection-code.d.ts +0 -67
  70. package/dist/user-connect/connection-code.js +0 -176
  71. package/dist/user-connect/connection-code.test.js +0 -213
  72. package/dist/user-connect/index.d.ts +0 -3
  73. package/dist/user-connect/index.js +0 -19
  74. package/dist/user-connect/user-connect.pvars.d.ts +0 -20
  75. package/dist/user-connect/user-connect.pvars.js +0 -63
  76. package/dist/user-connect/user-connect.pvars.test.js +0 -46
  77. package/dist/user-connect/user-connect.types.d.ts +0 -94
  78. package/dist/user-connect/user-connect.types.js +0 -68
  79. /package/dist/{user-connect/connection-code.test.d.ts → device-pairing/cpace.test.d.ts} +0 -0
  80. /package/dist/{user-connect/user-connect.pvars.test.d.ts → invites/group-approval.test.d.ts} +0 -0
@@ -12,6 +12,7 @@ export { PersistentContractRegistry } from "./persistent-registry";
12
12
  export { ContractRegistry, type IContractProviderRegistration } from "./registry";
13
13
  export { createRemoteContractEndpoint, getRemoteContractTransportFactory, type IRemoteContractHost, type IRemoteContractTarget, type RemoteContractTransportFactory, resolveRemoteTargetEndpoint, setRemoteContractTransportFactory, } from "./remote-contract-transport";
14
14
  export { DEVICE_OPERATIONS_CONTRACT_VERSION, DEVICE_OPERATIONS_MAX_QUERY_LENGTH, DEVICE_OPERATIONS_MAX_RESULT_BYTES, DEVICE_OPERATIONS_MAX_ROWS, DEVICE_OPERATIONS_MAX_TOOLS, type DeviceOperationCapability, deviceOperationsProviderPackageId, deviceOperationsToolIds, getDeviceOperationsContractDefinition, type IDeviceDatabaseQueryInput, type IDeviceDatabaseQueryResult, type IDeviceOperationStatus, type IDeviceToolListInput, type IDeviceToolLookupInput, type IDeviceToolLookupResult, type IDeviceToolRunInput, } from "./system/device-operations-contract";
15
+ export { getInvitesContractDefinition, type IAcceptInviteResult, type ICreatedInvite, type IInvitePreview, type IInvitesConsumer, INVITES_CONTRACT_VERSION, } from "./system/invites-contract";
15
16
  export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./system/logs-contract";
16
17
  export * from "./system/network-contracts";
17
18
  export { getToolAccessControlContractDefinition, type IToolAccessControlConsumer, TOOL_ACCESS_CONTROL_CONTRACT_VERSION, } from "./system/tool-access-control-contract";
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = exports.setRemoteContractTransportFactory = exports.resolveRemoteTargetEndpoint = exports.getRemoteContractTransportFactory = exports.createRemoteContractEndpoint = exports.ContractRegistry = exports.PersistentContractRegistry = exports.waitForHostContractTransport = exports.subscribeHostContractTransport = exports.registerHostContractTransport = exports.getHostContractTransport = exports.setSchemaToFieldsFn = exports.extractToolShape = exports.extractTableShape = exports.createLocalContractConsumer = exports.contractsSchema = exports.contractsMetaData = exports.ContractsTable = exports.Contracts = exports.inProcessTransportPair = exports.connectionContractTransport = exports.CONTRACT_REQUEST_CHANNEL = exports.CONTRACT_NOTIFY_CHANNEL = exports.verifyRemoteContractIdentity = exports.registerContractResolver = exports.isSelfTrustedContractCaller = exports.handleContractCall = exports.getContractResolver = exports.createUserContextContractProviderRouter = exports.createLocalUserContextContractProviderRouter = exports.authorizeRemoteContractCall = exports.sameUserContractPermissionCheck = exports.createRemoteContractConsumer = exports.createContractProviderSession = exports.createContractProviderEndpoint = exports.createContractProvider = exports.createContractConsumer = exports.CONTRACT_CALL_RPC = exports.contractProvidersSchema = exports.contractProvidersMetaData = exports.ContractProvidersTable = exports.ContractProviders = exports.createContractProviderRouter = exports.PackageBuilder = exports.definePackage = exports.ContractBuilder = void 0;
18
- exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = void 0;
18
+ exports.validateProviderSatisfiesContract = exports.validateImmutability = exports.validateAlsoImplements = exports.contractKey = exports.registerSystemContract = exports.listSystemContracts = exports.installSystemContracts = exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.INVITES_CONTRACT_VERSION = exports.getInvitesContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = void 0;
19
19
  var builder_1 = require("./builder");
20
20
  Object.defineProperty(exports, "ContractBuilder", { enumerable: true, get: function () { return builder_1.ContractBuilder; } });
21
21
  Object.defineProperty(exports, "definePackage", { enumerable: true, get: function () { return builder_1.definePackage; } });
@@ -83,6 +83,9 @@ Object.defineProperty(exports, "DEVICE_OPERATIONS_MAX_TOOLS", { enumerable: true
83
83
  Object.defineProperty(exports, "deviceOperationsProviderPackageId", { enumerable: true, get: function () { return device_operations_contract_1.deviceOperationsProviderPackageId; } });
84
84
  Object.defineProperty(exports, "deviceOperationsToolIds", { enumerable: true, get: function () { return device_operations_contract_1.deviceOperationsToolIds; } });
85
85
  Object.defineProperty(exports, "getDeviceOperationsContractDefinition", { enumerable: true, get: function () { return device_operations_contract_1.getDeviceOperationsContractDefinition; } });
86
+ var invites_contract_1 = require("./system/invites-contract");
87
+ Object.defineProperty(exports, "getInvitesContractDefinition", { enumerable: true, get: function () { return invites_contract_1.getInvitesContractDefinition; } });
88
+ Object.defineProperty(exports, "INVITES_CONTRACT_VERSION", { enumerable: true, get: function () { return invites_contract_1.INVITES_CONTRACT_VERSION; } });
86
89
  var logs_contract_1 = require("./system/logs-contract");
87
90
  Object.defineProperty(exports, "getLogsContractDefinition", { enumerable: true, get: function () { return logs_contract_1.getLogsContractDefinition; } });
88
91
  Object.defineProperty(exports, "LOGS_CONTRACT_VERSION", { enumerable: true, get: function () { return logs_contract_1.LOGS_CONTRACT_VERSION; } });
@@ -3,10 +3,12 @@
3
3
  * {@link registerSystemContract} side effect so the catalog is populated.
4
4
  */
5
5
  import "./device-operations-contract";
6
+ import "./invites-contract";
6
7
  import "./logs-contract";
7
8
  import "./network-contracts";
8
9
  import "./tool-access-control-contract";
9
10
  export { DEVICE_OPERATIONS_CONTRACT_VERSION, DEVICE_OPERATIONS_MAX_QUERY_LENGTH, DEVICE_OPERATIONS_MAX_RESULT_BYTES, DEVICE_OPERATIONS_MAX_ROWS, DEVICE_OPERATIONS_MAX_TOOLS, type DeviceOperationCapability, deviceOperationsProviderPackageId, deviceOperationsToolIds, getDeviceOperationsContractDefinition, type IDeviceDatabaseQueryInput, type IDeviceDatabaseQueryResult, type IDeviceOperationStatus, type IDeviceToolListInput, type IDeviceToolLookupInput, type IDeviceToolLookupResult, type IDeviceToolRunInput, } from "./device-operations-contract";
11
+ export { getInvitesContractDefinition, type IAcceptInviteResult, type ICreatedInvite, type IInvitePreview, type IInvitesConsumer, INVITES_CONTRACT_VERSION, } from "./invites-contract";
10
12
  export { getLogsContractDefinition, type ILogsConsumer, LOGS_CONTRACT_VERSION, resolveLogsContract, } from "./logs-contract";
11
13
  export * from "./network-contracts";
12
14
  export { getToolAccessControlContractDefinition, type IToolAccessControlConsumer, TOOL_ACCESS_CONTROL_CONTRACT_VERSION, } from "./tool-access-control-contract";
@@ -14,12 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = void 0;
17
+ exports.TOOL_ACCESS_CONTROL_CONTRACT_VERSION = exports.getToolAccessControlContractDefinition = exports.resolveLogsContract = exports.LOGS_CONTRACT_VERSION = exports.getLogsContractDefinition = exports.INVITES_CONTRACT_VERSION = exports.getInvitesContractDefinition = exports.getDeviceOperationsContractDefinition = exports.deviceOperationsToolIds = exports.deviceOperationsProviderPackageId = exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = void 0;
18
18
  /**
19
19
  * Built-in system contracts. Importing this barrel runs each module's
20
20
  * {@link registerSystemContract} side effect so the catalog is populated.
21
21
  */
22
22
  require("./device-operations-contract");
23
+ require("./invites-contract");
23
24
  require("./logs-contract");
24
25
  require("./network-contracts");
25
26
  require("./tool-access-control-contract");
@@ -32,6 +33,9 @@ Object.defineProperty(exports, "DEVICE_OPERATIONS_MAX_TOOLS", { enumerable: true
32
33
  Object.defineProperty(exports, "deviceOperationsProviderPackageId", { enumerable: true, get: function () { return device_operations_contract_1.deviceOperationsProviderPackageId; } });
33
34
  Object.defineProperty(exports, "deviceOperationsToolIds", { enumerable: true, get: function () { return device_operations_contract_1.deviceOperationsToolIds; } });
34
35
  Object.defineProperty(exports, "getDeviceOperationsContractDefinition", { enumerable: true, get: function () { return device_operations_contract_1.getDeviceOperationsContractDefinition; } });
36
+ var invites_contract_1 = require("./invites-contract");
37
+ Object.defineProperty(exports, "getInvitesContractDefinition", { enumerable: true, get: function () { return invites_contract_1.getInvitesContractDefinition; } });
38
+ Object.defineProperty(exports, "INVITES_CONTRACT_VERSION", { enumerable: true, get: function () { return invites_contract_1.INVITES_CONTRACT_VERSION; } });
35
39
  var logs_contract_1 = require("./logs-contract");
36
40
  Object.defineProperty(exports, "getLogsContractDefinition", { enumerable: true, get: function () { return logs_contract_1.getLogsContractDefinition; } });
37
41
  Object.defineProperty(exports, "LOGS_CONTRACT_VERSION", { enumerable: true, get: function () { return logs_contract_1.LOGS_CONTRACT_VERSION; } });
@@ -0,0 +1,121 @@
1
+ import type { GroupMemberRole } from "../../data/group-member-roles";
2
+ import type { IInvite, InviteStatus } from "../../data/invites";
3
+ import type { GroupInviteMode, PeersInvite } from "../../invites/invite-token";
4
+ import type { IContractConsumerBase } from "../contract-proxy";
5
+ import type { IContractDefinition } from "../types";
6
+ /** Version of the built-in System Invites contract. */
7
+ export declare const INVITES_CONTRACT_VERSION = 1;
8
+ /** A token the local user issued, with every encoding the UI and CLI need to share it. */
9
+ export interface ICreatedInvite {
10
+ inviteId: string;
11
+ token: PeersInvite;
12
+ encoded: string;
13
+ url: string;
14
+ deepLink: string;
15
+ }
16
+ /** Verified, human-readable summary of a token before the user acts on it. */
17
+ export interface IInvitePreview {
18
+ type: PeersInvite["type"];
19
+ inviter: PeersInvite["inviter"];
20
+ expiresAt: string;
21
+ expired: boolean;
22
+ /** Whether the inviter is already one of my contacts. */
23
+ knownContact: boolean;
24
+ group?: {
25
+ groupId: string;
26
+ name: string;
27
+ role: GroupMemberRole;
28
+ mode: GroupInviteMode;
29
+ /** Whether I am already a member of this group. */
30
+ alreadyMember: boolean;
31
+ };
32
+ }
33
+ /** Outcome of accepting a token or a pending inbound row. */
34
+ export interface IAcceptInviteResult {
35
+ inviteId: string;
36
+ /** `accepted` when the local side is done; `pending` when waiting on the other party. */
37
+ status: InviteStatus;
38
+ /** Whether the reply or request has left this device (`sent`) or awaits connectivity. */
39
+ deliveryState?: "queued" | "sent";
40
+ groupId?: string;
41
+ }
42
+ /**
43
+ * Local-only host contract for issuing, accepting, and resolving contact and group invites.
44
+ *
45
+ * Remote device connections must not resolve this contract; UI and CLI reach it over the
46
+ * host transport. Pending state lives in the `Invites` table, which UIs subscribe to directly.
47
+ */
48
+ export declare function getInvitesContractDefinition(): IContractDefinition;
49
+ /** Consumer-side TypeScript shape for System Invites. */
50
+ export interface IInvitesConsumer extends IContractConsumerBase {
51
+ tools: {
52
+ createContactInvite(input?: {
53
+ profile?: boolean;
54
+ expiresInMs?: number;
55
+ }): Promise<{
56
+ invite: ICreatedInvite;
57
+ }>;
58
+ createGroupInvite(input: {
59
+ groupId: string;
60
+ role?: GroupMemberRole;
61
+ mode?: GroupInviteMode;
62
+ expiresInMs?: number;
63
+ uses?: 1 | "unlimited";
64
+ }): Promise<{
65
+ invite: ICreatedInvite;
66
+ }>;
67
+ inviteContactToGroup(input: {
68
+ groupId: string;
69
+ userId: string;
70
+ role?: GroupMemberRole;
71
+ }): Promise<{
72
+ result: IAcceptInviteResult;
73
+ }>;
74
+ previewInvite(input: {
75
+ token: string;
76
+ }): Promise<{
77
+ preview: IInvitePreview;
78
+ }>;
79
+ acceptInvite(input: {
80
+ token?: string;
81
+ inviteId?: string;
82
+ trustLevel?: number;
83
+ }): Promise<{
84
+ result: IAcceptInviteResult;
85
+ }>;
86
+ declineInvite(input: {
87
+ inviteId: string;
88
+ }): Promise<{
89
+ result: IAcceptInviteResult;
90
+ }>;
91
+ approveJoinRequest(input: {
92
+ inviteId: string;
93
+ role?: GroupMemberRole;
94
+ }): Promise<{
95
+ result: IAcceptInviteResult;
96
+ }>;
97
+ denyJoinRequest(input: {
98
+ inviteId: string;
99
+ }): Promise<{
100
+ result: IAcceptInviteResult;
101
+ }>;
102
+ revokeInvite(input: {
103
+ inviteId: string;
104
+ }): Promise<{
105
+ result: IAcceptInviteResult;
106
+ }>;
107
+ regenerateProfileInvite(): Promise<{
108
+ invite: ICreatedInvite;
109
+ }>;
110
+ syncMailbox(): Promise<{
111
+ received: number;
112
+ sent: number;
113
+ }>;
114
+ listInvites(input?: {
115
+ status?: InviteStatus;
116
+ direction?: "in" | "out";
117
+ }): Promise<{
118
+ invites: IInvite[];
119
+ }>;
120
+ };
121
+ }
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.INVITES_CONTRACT_VERSION = void 0;
4
+ exports.getInvitesContractDefinition = getInvitesContractDefinition;
5
+ const system_ids_1 = require("../../system-ids");
6
+ const field_type_1 = require("../../types/field-type");
7
+ const system_contracts_1 = require("../system-contracts");
8
+ /** Version of the built-in System Invites contract. */
9
+ exports.INVITES_CONTRACT_VERSION = 1;
10
+ const field = (name, type, description, opts = {}) => ({ name, type, description, ...opts });
11
+ let definition;
12
+ /**
13
+ * Local-only host contract for issuing, accepting, and resolving contact and group invites.
14
+ *
15
+ * Remote device connections must not resolve this contract; UI and CLI reach it over the
16
+ * host transport. Pending state lives in the `Invites` table, which UIs subscribe to directly.
17
+ */
18
+ function getInvitesContractDefinition() {
19
+ definition ??= {
20
+ contractId: system_ids_1.invitesContractId,
21
+ version: exports.INVITES_CONTRACT_VERSION,
22
+ devTag: "dev",
23
+ name: "System Invites",
24
+ description: "Issue, preview, accept, approve, and revoke contact and group invites.",
25
+ tables: [],
26
+ tools: [
27
+ {
28
+ name: "createContactInvite",
29
+ usageDescription: "Issue a signed contact token as a link, QR payload, and deep link.",
30
+ inputFields: [
31
+ field("profile", field_type_1.FieldType.boolean, "Reusable profile QR (unlimited uses, 1 year).", {
32
+ optional: true,
33
+ }),
34
+ field("expiresInMs", field_type_1.FieldType.number, "Lifetime override in milliseconds.", {
35
+ optional: true,
36
+ }),
37
+ ],
38
+ outputFields: [field("invite", field_type_1.FieldType.object, "The issued invite and encodings.")],
39
+ },
40
+ {
41
+ name: "createGroupInvite",
42
+ usageDescription: "Issue a signed group link token in approve or open mode.",
43
+ inputFields: [
44
+ field("groupId", field_type_1.FieldType.id, "Group to invite into."),
45
+ field("role", field_type_1.FieldType.number, "Role granted on join.", { optional: true }),
46
+ field("mode", field_type_1.FieldType.string, "approve (default) or open.", { optional: true }),
47
+ field("expiresInMs", field_type_1.FieldType.number, "Lifetime override in milliseconds.", {
48
+ optional: true,
49
+ }),
50
+ field("uses", field_type_1.FieldType.string, "1 or unlimited (default unlimited).", {
51
+ optional: true,
52
+ }),
53
+ ],
54
+ outputFields: [field("invite", field_type_1.FieldType.object, "The issued invite and encodings.")],
55
+ },
56
+ {
57
+ name: "inviteContactToGroup",
58
+ usageDescription: "Send a known contact a ready-to-accept group approval (no link).",
59
+ inputFields: [
60
+ field("groupId", field_type_1.FieldType.id, "Group to invite into."),
61
+ field("userId", field_type_1.FieldType.id, "Contact to invite."),
62
+ field("role", field_type_1.FieldType.number, "Role granted on accept.", { optional: true }),
63
+ ],
64
+ outputFields: [field("result", field_type_1.FieldType.object, "Invite row id and delivery state.")],
65
+ },
66
+ {
67
+ name: "previewInvite",
68
+ usageDescription: "Verify a pasted or scanned token and describe it without acting.",
69
+ inputFields: [field("token", field_type_1.FieldType.string, "Token, invite URL, or peers:// link.")],
70
+ outputFields: [field("preview", field_type_1.FieldType.object, "Verified token summary.")],
71
+ },
72
+ {
73
+ name: "acceptInvite",
74
+ usageDescription: "Accept a token or a pending inbound invite row.",
75
+ inputFields: [
76
+ field("token", field_type_1.FieldType.string, "Token text when accepting from paste/scan.", {
77
+ optional: true,
78
+ }),
79
+ field("inviteId", field_type_1.FieldType.id, "Pending inbound row when accepting from the list.", {
80
+ optional: true,
81
+ }),
82
+ field("trustLevel", field_type_1.FieldType.number, "Trust to assign the new contact.", {
83
+ optional: true,
84
+ }),
85
+ ],
86
+ outputFields: [field("result", field_type_1.FieldType.object, "Resulting row status.")],
87
+ },
88
+ {
89
+ name: "declineInvite",
90
+ usageDescription: "Decline a pending inbound invite.",
91
+ inputFields: [field("inviteId", field_type_1.FieldType.id, "Pending inbound row.")],
92
+ outputFields: [field("result", field_type_1.FieldType.object, "Resulting row status.")],
93
+ },
94
+ {
95
+ name: "approveJoinRequest",
96
+ usageDescription: "Approve a pending join request and send the group approval.",
97
+ inputFields: [
98
+ field("inviteId", field_type_1.FieldType.id, "Pending inbound join request row."),
99
+ field("role", field_type_1.FieldType.number, "Role override.", { optional: true }),
100
+ ],
101
+ outputFields: [field("result", field_type_1.FieldType.object, "Resulting row status.")],
102
+ },
103
+ {
104
+ name: "denyJoinRequest",
105
+ usageDescription: "Deny a pending join request.",
106
+ inputFields: [field("inviteId", field_type_1.FieldType.id, "Pending inbound join request row.")],
107
+ outputFields: [field("result", field_type_1.FieldType.object, "Resulting row status.")],
108
+ },
109
+ {
110
+ name: "revokeInvite",
111
+ usageDescription: "Revoke one of my outstanding invites.",
112
+ inputFields: [field("inviteId", field_type_1.FieldType.id, "Outbound row to revoke.")],
113
+ outputFields: [field("result", field_type_1.FieldType.object, "Resulting row status.")],
114
+ },
115
+ {
116
+ name: "regenerateProfileInvite",
117
+ usageDescription: "Bump my invite epoch (revoking all tokens) and issue a new profile QR.",
118
+ inputFields: [],
119
+ outputFields: [field("invite", field_type_1.FieldType.object, "The new profile invite.")],
120
+ },
121
+ {
122
+ name: "syncMailbox",
123
+ usageDescription: "Fetch and process queued mailbox messages, then retry queued sends.",
124
+ inputFields: [],
125
+ outputFields: [
126
+ field("received", field_type_1.FieldType.number, "Messages processed."),
127
+ field("sent", field_type_1.FieldType.number, "Queued sends delivered."),
128
+ ],
129
+ },
130
+ {
131
+ name: "listInvites",
132
+ usageDescription: "List invite rows, optionally filtered by status and direction.",
133
+ inputFields: [
134
+ field("status", field_type_1.FieldType.string, "Row status filter.", { optional: true }),
135
+ field("direction", field_type_1.FieldType.string, "in or out.", { optional: true }),
136
+ ],
137
+ outputFields: [field("invites", field_type_1.FieldType.object, "Invite rows.", { isArray: true })],
138
+ },
139
+ ],
140
+ observables: [],
141
+ events: [],
142
+ };
143
+ return definition;
144
+ }
145
+ (0, system_contracts_1.registerSystemContract)({
146
+ providerPackageId: system_ids_1.peersSystemPackageId,
147
+ contractId: system_ids_1.invitesContractId,
148
+ version: exports.INVITES_CONTRACT_VERSION,
149
+ getDefinition: getInvitesContractDefinition,
150
+ });
@@ -0,0 +1,24 @@
1
+ import type { UserContext } from "../context/user-context";
2
+ import { type IGroup } from "./groups";
3
+ /** Options for {@link createGroup}. */
4
+ export interface CreateGroupInput {
5
+ /** Display name, 1–100 characters. */
6
+ name: string;
7
+ description?: string;
8
+ /** Bootstrap icon class, for example `bi-people-fill`. */
9
+ iconClassName?: string;
10
+ /** Use a specific id (tests); otherwise a new peer id is generated. */
11
+ groupId?: string;
12
+ }
13
+ /** Longest group name accepted by {@link createGroup}. */
14
+ export declare const GROUP_NAME_MAX_LENGTH = 100;
15
+ /**
16
+ * Create a group founded by the signed-in user: generate the group keypair, store its
17
+ * secret in the personal context, open the group data context, add the founder as a
18
+ * trusted member, and sign the `Groups` row into both the personal and group contexts.
19
+ *
20
+ * Runs on a host with signing enabled (`GroupsTable.enableGroupSigning`); UIs reach it
21
+ * through the host rather than duplicating the steps. Package seeding for the new context
22
+ * (for example `seedBundledPeersCore`) is the caller's responsibility.
23
+ */
24
+ export declare function createGroup(userContext: UserContext, input: CreateGroupInput): Promise<IGroup>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GROUP_NAME_MAX_LENGTH = void 0;
4
+ exports.createGroup = createGroup;
5
+ const socket_type_1 = require("../device/socket.type");
6
+ const keys_1 = require("../keys");
7
+ const utils_1 = require("../utils");
8
+ const group_member_roles_1 = require("./group-member-roles");
9
+ const group_members_1 = require("./group-members");
10
+ const group_secret_1 = require("./group-secret");
11
+ const groups_1 = require("./groups");
12
+ const user_trust_levels_1 = require("./user-trust-levels");
13
+ const users_1 = require("./users");
14
+ /** Longest group name accepted by {@link createGroup}. */
15
+ exports.GROUP_NAME_MAX_LENGTH = 100;
16
+ /**
17
+ * Create a group founded by the signed-in user: generate the group keypair, store its
18
+ * secret in the personal context, open the group data context, add the founder as a
19
+ * trusted member, and sign the `Groups` row into both the personal and group contexts.
20
+ *
21
+ * Runs on a host with signing enabled (`GroupsTable.enableGroupSigning`); UIs reach it
22
+ * through the host rather than duplicating the steps. Package seeding for the new context
23
+ * (for example `seedBundledPeersCore`) is the caller's responsibility.
24
+ */
25
+ async function createGroup(userContext, input) {
26
+ const name = input.name.trim();
27
+ if (!name)
28
+ throw new Error("Group name is required");
29
+ if (name.length > exports.GROUP_NAME_MAX_LENGTH) {
30
+ throw new Error(`Group name must be ${exports.GROUP_NAME_MAX_LENGTH} characters or less`);
31
+ }
32
+ const me = await userContext.getMe();
33
+ if (!me)
34
+ throw new Error("No signed-in user; cannot create a group");
35
+ const groupId = input.groupId ?? (0, utils_1.newid)();
36
+ const groupKeys = (0, keys_1.newKeys)();
37
+ const groupDataContext = userContext.getDataContext(groupId);
38
+ await (0, group_secret_1.saveGroupSecretKey)(userContext.userDataContext, groupId, groupKeys.secretKey, groupKeys);
39
+ await (0, users_1.Users)(groupDataContext).save(me);
40
+ await (0, user_trust_levels_1.setUserTrustLevel)(me.userId, socket_type_1.TrustLevel.Trusted, groupDataContext);
41
+ const group = await (0, groups_1.Groups)(userContext.userDataContext).signAndSave({
42
+ groupId,
43
+ name,
44
+ description: input.description?.trim() ?? "",
45
+ iconClassName: input.iconClassName?.trim() || "bi-people-fill",
46
+ founderUserId: me.userId,
47
+ disabled: false,
48
+ publicKey: groupKeys.publicKey,
49
+ publicBoxKey: groupKeys.publicBoxKey,
50
+ signature: "",
51
+ });
52
+ await (0, groups_1.Groups)(groupDataContext).signAndSave(group);
53
+ await (0, group_members_1.GroupMembers)(groupDataContext).signAndSave({
54
+ groupMemberId: (0, utils_1.newid)(),
55
+ groupId,
56
+ userId: me.userId,
57
+ role: group_member_roles_1.GroupMemberRole.Founder,
58
+ signature: "",
59
+ });
60
+ return group;
61
+ }
@@ -1,4 +1,5 @@
1
1
  import type { DataContext } from "../context/data-context";
2
+ import type { UserContext } from "../context/user-context";
2
3
  import { type IPublicKeys, type IPublicPrivateKeys } from "../keys";
3
4
  import { type IPersistentVar } from "./persistent-vars";
4
5
  /** Prefix used for each group's encrypted secret-key persistent variable. */
@@ -11,6 +12,15 @@ export declare function groupSecretKeyPvarName(groupId: string): string;
11
12
  * @throws When the secret is malformed or derives different signing/box public keys.
12
13
  */
13
14
  export declare function validateGroupSecretKey(secretKey: string, expected: IPublicKeys): IPublicPrivateKeys;
15
+ /**
16
+ * Read and validate a group's secret key from the user's personal context.
17
+ *
18
+ * The persistent variable is stored encrypted with the user's secret key; the decrypted
19
+ * value is checked against the signed group record before it is returned.
20
+ *
21
+ * @throws When the variable is missing, cannot be decrypted, or does not match the group.
22
+ */
23
+ export declare function readGroupSecretKey(userContext: UserContext, groupId: string, userSecretKey: string): Promise<string>;
14
24
  /**
15
25
  * Save a known-valid group secret in the user's personal context.
16
26
  *
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GROUP_SECRET_KEY_PVAR_PREFIX = void 0;
4
4
  exports.groupSecretKeyPvarName = groupSecretKeyPvarName;
5
5
  exports.validateGroupSecretKey = validateGroupSecretKey;
6
+ exports.readGroupSecretKey = readGroupSecretKey;
6
7
  exports.saveGroupSecretKey = saveGroupSecretKey;
7
8
  const keys_1 = require("../keys");
8
9
  const utils_1 = require("../utils");
10
+ const groups_1 = require("./groups");
9
11
  const persistent_vars_1 = require("./persistent-vars");
10
12
  /** Prefix used for each group's encrypted secret-key persistent variable. */
11
13
  exports.GROUP_SECRET_KEY_PVAR_PREFIX = "groupSecretKey_";
@@ -25,6 +27,30 @@ function validateGroupSecretKey(secretKey, expected) {
25
27
  }
26
28
  return derived;
27
29
  }
30
+ /**
31
+ * Read and validate a group's secret key from the user's personal context.
32
+ *
33
+ * The persistent variable is stored encrypted with the user's secret key; the decrypted
34
+ * value is checked against the signed group record before it is returned.
35
+ *
36
+ * @throws When the variable is missing, cannot be decrypted, or does not match the group.
37
+ */
38
+ async function readGroupSecretKey(userContext, groupId, userSecretKey) {
39
+ const encrypted = await (0, persistent_vars_1.PersistentVars)(userContext.userDataContext).getPersistentVarValue(groupSecretKeyPvarName(groupId));
40
+ if (!encrypted) {
41
+ throw new Error(`Could not find secret key for group ${groupId}`);
42
+ }
43
+ const groupSecretKey = (0, keys_1.decryptData)(encrypted, userSecretKey);
44
+ if (!groupSecretKey || typeof groupSecretKey !== "string") {
45
+ throw new Error("Could not decrypt group secret key");
46
+ }
47
+ const group = await (0, groups_1.Groups)(userContext.userDataContext).get(groupId);
48
+ if (!group) {
49
+ throw new Error(`Could not find group record for group ${groupId}`);
50
+ }
51
+ validateGroupSecretKey(groupSecretKey, group);
52
+ return groupSecretKey;
53
+ }
28
54
  /**
29
55
  * Save a known-valid group secret in the user's personal context.
30
56
  *
@@ -35,26 +35,6 @@ export declare function seedGroupContextFromShare(userContext: UserContext, grou
35
35
  * @returns boolean True if valid GroupShare structure
36
36
  */
37
37
  export declare function validateGroupShare(obj: any): obj is IGroupShare;
38
- /**
39
- * Estimates the size of a GroupShare object when serialized to JSON
40
- * @param groupShare The GroupShare object to estimate
41
- * @returns number Estimated size in characters
42
- */
43
- export declare function estimateGroupShareSize(groupShare: IGroupShare): number;
44
- /**
45
- * Checks if a GroupShare object would fit in a QR code of the specified version
46
- * @param groupShare The GroupShare object to check
47
- * @param qrVersion QR code version (10, 20, or 40)
48
- * @returns Object with size info and QR code compatibility
49
- */
50
- export declare function checkQRCodeCompatibility(groupShare: IGroupShare, qrVersion?: 10 | 20 | 40): {
51
- size: number;
52
- maxSize: number;
53
- fits: boolean;
54
- usagePercent: number;
55
- qrVersion: 10 | 20 | 40;
56
- memberCount: number;
57
- };
58
38
  /**
59
39
  * Copies text to clipboard with fallback handling
60
40
  * @param text Text to copy to clipboard
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateGroupShare = generateGroupShare;
4
4
  exports.seedGroupContextFromShare = seedGroupContextFromShare;
5
5
  exports.validateGroupShare = validateGroupShare;
6
- exports.estimateGroupShareSize = estimateGroupShareSize;
7
- exports.checkQRCodeCompatibility = checkQRCodeCompatibility;
8
6
  exports.copyToClipboard = copyToClipboard;
9
7
  const __1 = require("..");
10
8
  const user_context_singleton_1 = require("../context/user-context-singleton");
@@ -144,39 +142,6 @@ function validateGroupShare(obj) {
144
142
  }
145
143
  return true;
146
144
  }
147
- /**
148
- * Estimates the size of a GroupShare object when serialized to JSON
149
- * @param groupShare The GroupShare object to estimate
150
- * @returns number Estimated size in characters
151
- */
152
- function estimateGroupShareSize(groupShare) {
153
- return JSON.stringify(groupShare).length;
154
- }
155
- /**
156
- * Checks if a GroupShare object would fit in a QR code of the specified version
157
- * @param groupShare The GroupShare object to check
158
- * @param qrVersion QR code version (10, 20, or 40)
159
- * @returns Object with size info and QR code compatibility
160
- */
161
- function checkQRCodeCompatibility(groupShare, qrVersion = 20) {
162
- const size = estimateGroupShareSize(groupShare);
163
- const limits = {
164
- 10: 1273, // Version 10 limit
165
- 20: 3057, // Version 20 limit
166
- 40: 7089, // Version 40 limit
167
- };
168
- const maxSize = limits[qrVersion];
169
- const fits = size <= maxSize;
170
- const usagePercent = Math.round((size / maxSize) * 100);
171
- return {
172
- size,
173
- maxSize,
174
- fits,
175
- usagePercent,
176
- qrVersion,
177
- memberCount: groupShare.groupMembers.length,
178
- };
179
- }
180
145
  /**
181
146
  * Copies text to clipboard with fallback handling
182
147
  * @param text Text to copy to clipboard
@@ -2,6 +2,7 @@ export * from "./access-level";
2
2
  export * from "./assistants";
3
3
  export * from "./change-tracking";
4
4
  export * from "./channels";
5
+ export * from "./create-group";
5
6
  export * from "./device-sync-info";
6
7
  export * from "./devices";
7
8
  export * from "./embeddings";
@@ -12,6 +13,7 @@ export * from "./group-permissions";
12
13
  export * from "./group-secret";
13
14
  export * from "./group-share";
14
15
  export * from "./groups";
16
+ export * from "./invites";
15
17
  export * from "./messages";
16
18
  export * from "./package-table-identity";
17
19
  export * from "./package-version-resolver";
@@ -18,6 +18,7 @@ __exportStar(require("./access-level"), exports);
18
18
  __exportStar(require("./assistants"), exports);
19
19
  __exportStar(require("./change-tracking"), exports);
20
20
  __exportStar(require("./channels"), exports);
21
+ __exportStar(require("./create-group"), exports);
21
22
  __exportStar(require("./device-sync-info"), exports);
22
23
  __exportStar(require("./devices"), exports);
23
24
  __exportStar(require("./embeddings"), exports);
@@ -28,6 +29,7 @@ __exportStar(require("./group-permissions"), exports);
28
29
  __exportStar(require("./group-secret"), exports);
29
30
  __exportStar(require("./group-share"), exports);
30
31
  __exportStar(require("./groups"), exports);
32
+ __exportStar(require("./invites"), exports);
31
33
  __exportStar(require("./messages"), exports);
32
34
  __exportStar(require("./package-table-identity"), exports);
33
35
  __exportStar(require("./package-version-resolver"), exports);