@peers-app/peers-sdk 0.19.14 → 0.20.1

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 (86) hide show
  1. package/dist/contracts/__tests__/builder.test.js +24 -0
  2. package/dist/contracts/__tests__/contract-events.test.d.ts +1 -0
  3. package/dist/contracts/__tests__/contract-events.test.js +199 -0
  4. package/dist/contracts/__tests__/contract-observables.test.d.ts +1 -0
  5. package/dist/contracts/__tests__/contract-observables.test.js +290 -0
  6. package/dist/contracts/__tests__/contract-provider-router.test.d.ts +1 -0
  7. package/dist/contracts/__tests__/contract-provider-router.test.js +193 -0
  8. package/dist/contracts/__tests__/contract-proxy.test.d.ts +1 -0
  9. package/dist/contracts/__tests__/contract-proxy.test.js +424 -0
  10. package/dist/contracts/__tests__/contract-resolvers.test.d.ts +1 -0
  11. package/dist/contracts/__tests__/contract-resolvers.test.js +148 -0
  12. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.d.ts +1 -0
  13. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.js +353 -0
  14. package/dist/contracts/__tests__/contract-table-events.test.d.ts +1 -0
  15. package/dist/contracts/__tests__/contract-table-events.test.js +209 -0
  16. package/dist/contracts/__tests__/contract-transport.test.d.ts +1 -0
  17. package/dist/contracts/__tests__/contract-transport.test.js +163 -0
  18. package/dist/contracts/__tests__/persistent-registry.test.d.ts +1 -0
  19. package/dist/contracts/__tests__/persistent-registry.test.js +109 -0
  20. package/dist/contracts/__tests__/playground.test.d.ts +1 -0
  21. package/dist/contracts/__tests__/playground.test.js +213 -0
  22. package/dist/contracts/__tests__/validate.test.js +122 -0
  23. package/dist/contracts/builder.d.ts +9 -1
  24. package/dist/contracts/builder.js +13 -0
  25. package/dist/contracts/contract-provider-router.d.ts +72 -0
  26. package/dist/contracts/contract-provider-router.js +164 -0
  27. package/dist/contracts/contract-proxy.d.ts +333 -0
  28. package/dist/contracts/contract-proxy.js +663 -0
  29. package/dist/contracts/contract-resolvers.d.ts +66 -0
  30. package/dist/contracts/contract-resolvers.js +138 -0
  31. package/dist/contracts/contract-transport.d.ts +94 -0
  32. package/dist/contracts/contract-transport.js +159 -0
  33. package/dist/contracts/contracts.table.d.ts +1 -1
  34. package/dist/contracts/contracts.table.js +2 -2
  35. package/dist/contracts/index.d.ts +7 -1
  36. package/dist/contracts/index.js +34 -1
  37. package/dist/contracts/persistent-registry.js +3 -1
  38. package/dist/contracts/system/device-operations-contract.d.ts +72 -0
  39. package/dist/contracts/system/device-operations-contract.js +110 -0
  40. package/dist/contracts/system/logs-contract.d.ts +24 -0
  41. package/dist/contracts/system/logs-contract.js +60 -0
  42. package/dist/contracts/types.d.ts +27 -4
  43. package/dist/contracts/validate.d.ts +2 -2
  44. package/dist/contracts/validate.js +44 -2
  45. package/dist/data/assistants.d.ts +4 -4
  46. package/dist/data/channels.d.ts +1 -1
  47. package/dist/data/devices.d.ts +1 -1
  48. package/dist/data/embeddings.d.ts +1 -1
  49. package/dist/data/group-secret.d.ts +21 -0
  50. package/dist/data/group-secret.js +53 -0
  51. package/dist/data/index.d.ts +1 -0
  52. package/dist/data/index.js +1 -0
  53. package/dist/data/messages.d.ts +1 -1
  54. package/dist/data/orm/decorators.d.ts +6 -0
  55. package/dist/data/orm/decorators.js +21 -0
  56. package/dist/data/package-versions.d.ts +2 -2
  57. package/dist/data/peer-types.d.ts +1 -1
  58. package/dist/data/persistent-vars.d.ts +17 -0
  59. package/dist/data/persistent-vars.js +115 -35
  60. package/dist/data/persistent-vars.migration.test.d.ts +1 -0
  61. package/dist/data/persistent-vars.migration.test.js +133 -0
  62. package/dist/data/table-definitions-table.d.ts +1 -1
  63. package/dist/data/tool-tests.d.ts +1 -1
  64. package/dist/data/tools.d.ts +1 -1
  65. package/dist/data/user-trust-levels.d.ts +3 -1
  66. package/dist/data/user-trust-levels.js +2 -1
  67. package/dist/data/user-trust-levels.test.d.ts +1 -0
  68. package/dist/data/user-trust-levels.test.js +37 -0
  69. package/dist/data/voice-messages.d.ts +1 -1
  70. package/dist/data/workflow-logs.d.ts +1 -1
  71. package/dist/data/workflow-runs.d.ts +2 -2
  72. package/dist/data/workflows.d.ts +3 -3
  73. package/dist/device/binary-peer-connection-v2.d.ts +2 -0
  74. package/dist/device/binary-peer-connection-v2.js +12 -2
  75. package/dist/device/binary-peer-connection-v2.test.js +23 -0
  76. package/dist/device/get-trust-level-fn.d.ts +6 -0
  77. package/dist/device/get-trust-level-fn.js +12 -7
  78. package/dist/device/get-trust-level-fn.test.js +16 -2
  79. package/dist/logging/console-logs.table.d.ts +3 -0
  80. package/dist/logging/console-logs.table.js +2 -1
  81. package/dist/rpc-types.d.ts +37 -0
  82. package/dist/rpc-types.js +13 -0
  83. package/dist/system-ids.d.ts +25 -0
  84. package/dist/system-ids.js +26 -1
  85. package/dist/types/workflow.d.ts +4 -4
  86. package/package.json +1 -1
@@ -0,0 +1,72 @@
1
+ import type { ITool } from "../../data/tools";
2
+ import type { IContractDefinition } from "../types";
3
+ /** Version of the built-in System Device Operations contract. */
4
+ export declare const DEVICE_OPERATIONS_CONTRACT_VERSION = 1;
5
+ /** Maximum SQL text accepted by the remote database operation. */
6
+ export declare const DEVICE_OPERATIONS_MAX_QUERY_LENGTH = 20000;
7
+ /** Maximum rows returned by one remote database operation. */
8
+ export declare const DEVICE_OPERATIONS_MAX_ROWS = 500;
9
+ /** Maximum serialized result size returned by one remote database operation. */
10
+ export declare const DEVICE_OPERATIONS_MAX_RESULT_BYTES = 1000000;
11
+ /** Maximum tools returned by one remote tool-list operation. */
12
+ export declare const DEVICE_OPERATIONS_MAX_TOOLS = 100;
13
+ /** Stable IDs for the live tools implementing System Device Operations v1. */
14
+ export declare const deviceOperationsToolIds: {
15
+ readonly getDeviceStatus: "00mriijkhr4iptdefp4a7ifcq";
16
+ readonly queryDatabase: "00mriijkhrd54n33ey0omeejo";
17
+ readonly listTools: "00mriijkhr4fpyd70nyo5iqlq";
18
+ readonly getTool: "00mriijkhrid4wpf89i4ikvay";
19
+ readonly runTool: "00mriijkhrfequch2qaeoihol";
20
+ };
21
+ /** Portable operations supported by System Device Operations v1. */
22
+ export type DeviceOperationCapability = "device-status" | "database-query" | "tool-list" | "tool-get" | "tool-run";
23
+ /** Status and capability information returned by a remote device. */
24
+ export interface IDeviceOperationStatus {
25
+ deviceId: string;
26
+ userId: string;
27
+ dataContextId: string;
28
+ contractVersion: number;
29
+ capabilities: DeviceOperationCapability[];
30
+ limits: {
31
+ maxQueryLength: number;
32
+ maxRows: number;
33
+ maxResultBytes: number;
34
+ maxTools: number;
35
+ };
36
+ }
37
+ /** Input for a bounded, read-only remote SQLite query. */
38
+ export interface IDeviceDatabaseQueryInput {
39
+ query: string;
40
+ }
41
+ /** Serializable result from a bounded, read-only remote SQLite query. */
42
+ export interface IDeviceDatabaseQueryResult {
43
+ columns: string[];
44
+ rows: unknown[][];
45
+ rowCount: number;
46
+ truncated: boolean;
47
+ }
48
+ /** Input for listing tools available in the selected data context. */
49
+ export interface IDeviceToolListInput {
50
+ limit?: number;
51
+ }
52
+ /** Input for exact-ID, exact-name, or unambiguous-text tool lookup. */
53
+ export interface IDeviceToolLookupInput {
54
+ toolIdOrName: string;
55
+ }
56
+ /** Input for running a tool on the remote device. */
57
+ export interface IDeviceToolRunInput extends IDeviceToolLookupInput {
58
+ args?: Record<string, unknown>;
59
+ assistantId?: string;
60
+ }
61
+ /** Result of an unambiguous tool lookup, or `null` when no tool matched. */
62
+ export type IDeviceToolLookupResult = ITool | null;
63
+ /**
64
+ * Return the portable, owner-authorized device administration contract shape.
65
+ *
66
+ * The contract intentionally exposes explicit operations instead of arbitrary table,
67
+ * filesystem, shell, UI, or lifecycle access. Authorization is supplied by the verified
68
+ * connection host before the live resolver is invoked.
69
+ */
70
+ export declare function getDeviceOperationsContractDefinition(): IContractDefinition;
71
+ /** Package ID used by live System Device Operations tool instances. */
72
+ export declare const deviceOperationsProviderPackageId = "000peers0system0000000001";
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deviceOperationsProviderPackageId = exports.deviceOperationsToolIds = exports.DEVICE_OPERATIONS_MAX_TOOLS = exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = exports.DEVICE_OPERATIONS_MAX_ROWS = exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = exports.DEVICE_OPERATIONS_CONTRACT_VERSION = void 0;
4
+ exports.getDeviceOperationsContractDefinition = getDeviceOperationsContractDefinition;
5
+ const system_ids_1 = require("../../system-ids");
6
+ const field_type_1 = require("../../types/field-type");
7
+ /** Version of the built-in System Device Operations contract. */
8
+ exports.DEVICE_OPERATIONS_CONTRACT_VERSION = 1;
9
+ /** Maximum SQL text accepted by the remote database operation. */
10
+ exports.DEVICE_OPERATIONS_MAX_QUERY_LENGTH = 20_000;
11
+ /** Maximum rows returned by one remote database operation. */
12
+ exports.DEVICE_OPERATIONS_MAX_ROWS = 500;
13
+ /** Maximum serialized result size returned by one remote database operation. */
14
+ exports.DEVICE_OPERATIONS_MAX_RESULT_BYTES = 1_000_000;
15
+ /** Maximum tools returned by one remote tool-list operation. */
16
+ exports.DEVICE_OPERATIONS_MAX_TOOLS = 100;
17
+ /** Stable IDs for the live tools implementing System Device Operations v1. */
18
+ exports.deviceOperationsToolIds = {
19
+ getDeviceStatus: "00mriijkhr4iptdefp4a7ifcq",
20
+ queryDatabase: "00mriijkhrd54n33ey0omeejo",
21
+ listTools: "00mriijkhr4fpyd70nyo5iqlq",
22
+ getTool: "00mriijkhrid4wpf89i4ikvay",
23
+ runTool: "00mriijkhrfequch2qaeoihol",
24
+ };
25
+ const field = (name, type, description, opts = {}) => ({ name, type, description, ...opts });
26
+ let definition;
27
+ /**
28
+ * Return the portable, owner-authorized device administration contract shape.
29
+ *
30
+ * The contract intentionally exposes explicit operations instead of arbitrary table,
31
+ * filesystem, shell, UI, or lifecycle access. Authorization is supplied by the verified
32
+ * connection host before the live resolver is invoked.
33
+ */
34
+ function getDeviceOperationsContractDefinition() {
35
+ definition ??= {
36
+ contractId: system_ids_1.deviceOperationsContractId,
37
+ version: exports.DEVICE_OPERATIONS_CONTRACT_VERSION,
38
+ devTag: "dev",
39
+ name: "System Device Operations",
40
+ description: "Owner-authorized status, bounded read-only database, and installed-tool operations.",
41
+ tables: [],
42
+ tools: [
43
+ {
44
+ name: "getDeviceStatus",
45
+ usageDescription: "Return this device's identity, supported operations, and limits.",
46
+ inputFields: [],
47
+ outputFields: [
48
+ field("deviceId", field_type_1.FieldType.id, "The provider device ID."),
49
+ field("userId", field_type_1.FieldType.id, "The provider user ID."),
50
+ field("dataContextId", field_type_1.FieldType.id, "The selected data context ID."),
51
+ field("contractVersion", field_type_1.FieldType.number, "The supported contract version."),
52
+ field("capabilities", field_type_1.FieldType.string, "Supported portable operations.", {
53
+ isArray: true,
54
+ }),
55
+ field("limits", field_type_1.FieldType.object, "Provider-enforced request and result limits."),
56
+ ],
57
+ },
58
+ {
59
+ name: "queryDatabase",
60
+ usageDescription: "Run one bounded read-only SELECT or approved PRAGMA query.",
61
+ inputFields: [field("query", field_type_1.FieldType.string, "One read-only SQLite statement.")],
62
+ outputFields: [
63
+ field("columns", field_type_1.FieldType.string, "Result column names.", { isArray: true }),
64
+ field("rows", field_type_1.FieldType.any, "Serializable result rows.", { isArray: true }),
65
+ field("rowCount", field_type_1.FieldType.number, "Number of returned rows."),
66
+ field("truncated", field_type_1.FieldType.boolean, "Whether rows were omitted by provider limits."),
67
+ ],
68
+ },
69
+ {
70
+ name: "listTools",
71
+ usageDescription: "List installed tools in the selected data context.",
72
+ inputFields: [
73
+ field("limit", field_type_1.FieldType.number, "Maximum tools to return.", { optional: true }),
74
+ ],
75
+ outputFields: [
76
+ field("tools", field_type_1.FieldType.object, "Installed tool definitions.", { isArray: true }),
77
+ ],
78
+ },
79
+ {
80
+ name: "getTool",
81
+ usageDescription: "Resolve a tool by exact ID, exact name, or unambiguous text.",
82
+ inputFields: [
83
+ field("toolIdOrName", field_type_1.FieldType.string, "Tool ID, exact name, or search text."),
84
+ ],
85
+ outputFields: [
86
+ field("tool", field_type_1.FieldType.object, "The matching tool definition, or null.", {
87
+ optional: true,
88
+ }),
89
+ ],
90
+ },
91
+ {
92
+ name: "runTool",
93
+ usageDescription: "Resolve and run an installed tool in the selected data context.",
94
+ inputFields: [
95
+ field("toolIdOrName", field_type_1.FieldType.string, "Tool ID, exact name, or search text."),
96
+ field("args", field_type_1.FieldType.object, "Tool input arguments.", { optional: true }),
97
+ field("assistantId", field_type_1.FieldType.id, "Optional assistant execution context.", {
98
+ optional: true,
99
+ }),
100
+ ],
101
+ outputFields: [field("result", field_type_1.FieldType.any, "The tool execution result.")],
102
+ },
103
+ ],
104
+ observables: [],
105
+ events: [],
106
+ };
107
+ return definition;
108
+ }
109
+ /** Package ID used by live System Device Operations tool instances. */
110
+ exports.deviceOperationsProviderPackageId = system_ids_1.peersSystemPackageId;
@@ -0,0 +1,24 @@
1
+ import type { DataContext } from "../../context/data-context";
2
+ import type { IContractResolution } from "../contract-proxy";
3
+ import type { IContractDefinition } from "../types";
4
+ /** Version of the built-in System Logs contract. */
5
+ export declare const LOGS_CONTRACT_VERSION = 1;
6
+ /**
7
+ * The first built-in **system contract**: read and write the local device's console logs.
8
+ *
9
+ * It declares only the `ConsoleLogs` table — the table's own methods (`list`, `count`,
10
+ * `deleteOldLogs`, …) are the entire surface we need, so no bespoke tools are required.
11
+ * The table shape is derived from {@link consoleLogSchema} so the contract stays accurate.
12
+ *
13
+ * Built lazily and memoized: reading `consoleLogsMetaData` / `consoleLogSchema` at module
14
+ * load would race the import cycle between the logging table and the SDK barrel, so we defer
15
+ * construction until first use (well after all modules have finished initializing).
16
+ */
17
+ export declare function getLogsContractDefinition(): IContractDefinition;
18
+ /**
19
+ * Resolve the logs contract to its live implementation for a data context: the
20
+ * `ConsoleLogs` table backing that context.
21
+ */
22
+ export declare function resolveLogsContract(ctx: {
23
+ dataContext: DataContext;
24
+ }): IContractResolution;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOGS_CONTRACT_VERSION = void 0;
4
+ exports.getLogsContractDefinition = getLogsContractDefinition;
5
+ exports.resolveLogsContract = resolveLogsContract;
6
+ const user_context_singleton_1 = require("../../context/user-context-singleton");
7
+ const types_1 = require("../../data/orm/types");
8
+ const console_logs_table_1 = require("../../logging/console-logs.table");
9
+ const system_ids_1 = require("../../system-ids");
10
+ const contract_resolvers_1 = require("../contract-resolvers");
11
+ /** Version of the built-in System Logs contract. */
12
+ exports.LOGS_CONTRACT_VERSION = 1;
13
+ let _definition;
14
+ /**
15
+ * The first built-in **system contract**: read and write the local device's console logs.
16
+ *
17
+ * It declares only the `ConsoleLogs` table — the table's own methods (`list`, `count`,
18
+ * `deleteOldLogs`, …) are the entire surface we need, so no bespoke tools are required.
19
+ * The table shape is derived from {@link consoleLogSchema} so the contract stays accurate.
20
+ *
21
+ * Built lazily and memoized: reading `consoleLogsMetaData` / `consoleLogSchema` at module
22
+ * load would race the import cycle between the logging table and the SDK barrel, so we defer
23
+ * construction until first use (well after all modules have finished initializing).
24
+ */
25
+ function getLogsContractDefinition() {
26
+ if (!_definition) {
27
+ _definition = {
28
+ contractId: system_ids_1.logsContractId,
29
+ version: exports.LOGS_CONTRACT_VERSION,
30
+ devTag: "dev",
31
+ name: "System Logs",
32
+ description: "Read and write the local device's console logs.",
33
+ tables: [
34
+ {
35
+ name: console_logs_table_1.consoleLogsMetaData.name,
36
+ description: console_logs_table_1.consoleLogsMetaData.description,
37
+ primaryKeyName: console_logs_table_1.consoleLogsMetaData.primaryKeyName,
38
+ fields: (0, types_1.schemaToFields)(console_logs_table_1.consoleLogSchema),
39
+ },
40
+ ],
41
+ tools: [],
42
+ observables: [],
43
+ events: [],
44
+ };
45
+ }
46
+ return _definition;
47
+ }
48
+ /**
49
+ * Resolve the logs contract to its live implementation for a data context: the
50
+ * `ConsoleLogs` table backing that context.
51
+ */
52
+ function resolveLogsContract(ctx) {
53
+ const consoleLogs = (0, user_context_singleton_1.getTableContainer)(ctx.dataContext).getTable(console_logs_table_1.consoleLogsMetaData, console_logs_table_1.consoleLogSchema, console_logs_table_1.ConsoleLogsTable);
54
+ return {
55
+ contractId: system_ids_1.logsContractId,
56
+ version: exports.LOGS_CONTRACT_VERSION,
57
+ tables: { [console_logs_table_1.consoleLogsMetaData.name]: consoleLogs },
58
+ };
59
+ }
60
+ (0, contract_resolvers_1.registerContractResolver)(system_ids_1.logsContractId, exports.LOGS_CONTRACT_VERSION, resolveLogsContract);
@@ -1,11 +1,12 @@
1
1
  import type { Table } from "../data/orm/table";
2
2
  import type { ITableDefinition } from "../data/orm/table-definitions.type";
3
3
  import type { IToolInstance } from "../data/tools";
4
+ import type { Event } from "../events";
4
5
  import type { Observable } from "../observable";
5
6
  import type { FieldType, IField } from "../types/field-type";
6
7
  /**
7
- * A versioned interface definition declaring the shape of tables, tools, and
8
- * observables that a package provides. Pure data — no executable code.
8
+ * A versioned interface definition declaring the shape of tables, tools,
9
+ * observables, and events that a package provides. Pure data — no executable code.
9
10
  */
10
11
  export interface IContractDefinition {
11
12
  contractId: string;
@@ -17,6 +18,12 @@ export interface IContractDefinition {
17
18
  tables: IContractTable[];
18
19
  tools: IContractTool[];
19
20
  observables: IContractObservable[];
21
+ /**
22
+ * Events a provider may emit and consumers may subscribe to. Optional so
23
+ * existing contract definitions stay valid; the {@link ContractBuilder} always
24
+ * emits an array (possibly empty) and consumers read `contract.events ?? []`.
25
+ */
26
+ events?: IContractEvent[];
20
27
  }
21
28
  /** Table shape within a contract — derived from ITableMetaData + IField[]. */
22
29
  export interface IContractTable {
@@ -39,6 +46,18 @@ export interface IContractObservable {
39
46
  valueType: FieldType;
40
47
  writable: boolean;
41
48
  }
49
+ /**
50
+ * A generic event a contract provider may emit. Consumers subscribe by name; the
51
+ * provider only forwards payloads over the transport while at least one consumer
52
+ * has an active subscription (see the provider session). Pure shape — the live
53
+ * {@link Event} is supplied at resolution time in {@link IContractResolution.events}.
54
+ */
55
+ export interface IContractEvent {
56
+ name: string;
57
+ description: string;
58
+ /** Shape of the payload delivered to subscribers when the event fires. */
59
+ payloadFields: IField[];
60
+ }
42
61
  /**
43
62
  * A reference to a contract that a package wants to consume.
44
63
  * Recorded during `definePackage` and checked at install time.
@@ -46,6 +65,7 @@ export interface IContractObservable {
46
65
  export interface IConsumedContract {
47
66
  contractId: string;
48
67
  version: number;
68
+ optional?: boolean;
49
69
  }
50
70
  /**
51
71
  * Declares that the owning contract's implementation also satisfies another
@@ -86,15 +106,18 @@ export interface IResolvedContract {
86
106
  tables: Record<string, Table<any>>;
87
107
  tools: Record<string, IToolInstance>;
88
108
  observables: Record<string, Observable<any>>;
109
+ /** Live events the provider forwards from, keyed by contract event name. */
110
+ events?: Record<string, Event<any>>;
89
111
  }
90
112
  /** Outcome of a validation check. */
91
113
  export interface IValidationResult {
92
114
  valid: boolean;
93
115
  errors: IValidationError[];
94
116
  }
117
+ /** One incompatibility found while validating a contract definition or provider. */
95
118
  export interface IValidationError {
96
- /** Which element failed: `'table'`, `'tool'`, `'observable'`, `'contract'` */
97
- kind: "table" | "tool" | "observable" | "contract" | "field";
119
+ /** Which contract element failed validation. */
120
+ kind: "table" | "tool" | "observable" | "event" | "contract" | "field";
98
121
  /** Name of the element (table name, tool name, etc.) */
99
122
  name: string;
100
123
  message: string;
@@ -1,8 +1,8 @@
1
1
  import type { IAlsoImplementsDeclaration, IContractDefinition, IValidationResult } from "./types";
2
2
  /**
3
3
  * Validate that an implementation contract satisfies a target contract shape.
4
- * The implementation must be a superset: all contract tables, tools, and
5
- * observables must be present with compatible shapes.
4
+ * The implementation must be a superset: all contract tables, tools,
5
+ * observables, and events must be present with compatible shapes.
6
6
  */
7
7
  export declare function validateProviderSatisfiesContract(impl: IContractDefinition, contract: IContractDefinition): IValidationResult;
8
8
  /**
@@ -114,10 +114,36 @@ function validateToolFields(contractTool, implTool, direction) {
114
114
  }
115
115
  return errors;
116
116
  }
117
+ function validateEventFields(contractEvent, implEvent) {
118
+ const errors = [];
119
+ const implFieldMap = new Map(implEvent.payloadFields.map((field) => [field.name, field]));
120
+ for (const contractField of contractEvent.payloadFields) {
121
+ const implField = implFieldMap.get(contractField.name);
122
+ if (!implField) {
123
+ if (!contractField.optional) {
124
+ errors.push({
125
+ kind: "field",
126
+ name: `${contractEvent.name}.payload.${contractField.name}`,
127
+ message: `Required payload field '${contractField.name}' missing from implementation event '${implEvent.name}'`,
128
+ });
129
+ }
130
+ continue;
131
+ }
132
+ const compat = isFieldCompatible(contractField, implField);
133
+ if (compat) {
134
+ errors.push({
135
+ kind: "field",
136
+ name: `${contractEvent.name}.payload.${contractField.name}`,
137
+ message: `Payload field '${contractField.name}' in event '${implEvent.name}': ${compat}`,
138
+ });
139
+ }
140
+ }
141
+ return errors;
142
+ }
117
143
  /**
118
144
  * Validate that an implementation contract satisfies a target contract shape.
119
- * The implementation must be a superset: all contract tables, tools, and
120
- * observables must be present with compatible shapes.
145
+ * The implementation must be a superset: all contract tables, tools,
146
+ * observables, and events must be present with compatible shapes.
121
147
  */
122
148
  function validateProviderSatisfiesContract(impl, contract) {
123
149
  const errors = [];
@@ -184,6 +210,20 @@ function validateProviderSatisfiesContract(impl, contract) {
184
210
  });
185
211
  }
186
212
  }
213
+ // Events
214
+ const implEventMap = new Map((impl.events ?? []).map((event) => [event.name, event]));
215
+ for (const contractEvent of contract.events ?? []) {
216
+ const implEvent = implEventMap.get(contractEvent.name);
217
+ if (!implEvent) {
218
+ errors.push({
219
+ kind: "event",
220
+ name: contractEvent.name,
221
+ message: `Event '${contractEvent.name}' required by contract but not provided by implementation`,
222
+ });
223
+ continue;
224
+ }
225
+ errors.push(...validateEventFields(contractEvent, implEvent));
226
+ }
187
227
  return errors.length === 0 ? ok() : fail(errors);
188
228
  }
189
229
  /**
@@ -212,11 +252,13 @@ function validateImmutability(existing, incoming) {
212
252
  tables: existing.tables,
213
253
  tools: existing.tools,
214
254
  observables: existing.observables,
255
+ events: existing.events ?? [],
215
256
  });
216
257
  const incomingShape = JSON.stringify({
217
258
  tables: incoming.tables,
218
259
  tools: incoming.tools,
219
260
  observables: incoming.observables,
261
+ events: incoming.events ?? [],
220
262
  });
221
263
  if (existingShape !== incomingShape) {
222
264
  return fail([
@@ -18,8 +18,8 @@ export declare const assistantSchema: z.ZodObject<{
18
18
  packageId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
19
19
  }, "strip", z.ZodTypeAny, {
20
20
  name: string;
21
- createdAt: Date;
22
21
  assistantId: string;
22
+ createdAt: Date;
23
23
  assistantRunnerToolId: string;
24
24
  assistantRunnerConfig: {} & {
25
25
  [k: string]: any;
@@ -42,10 +42,10 @@ export declare const assistantSchema: z.ZodObject<{
42
42
  toolInclusionStrategy?: ToolInclusionStrategy | undefined;
43
43
  }>;
44
44
  export type IAssistant = z.infer<typeof assistantSchema>;
45
- export declare function Assistants(dataContext?: DataContext): import("./orm").Table<{
45
+ export declare function Assistants(dataContext?: DataContext): import("..").Table<{
46
46
  name: string;
47
- createdAt: Date;
48
47
  assistantId: string;
48
+ createdAt: Date;
49
49
  assistantRunnerToolId: string;
50
50
  assistantRunnerConfig: {} & {
51
51
  [k: string]: any;
@@ -68,8 +68,8 @@ export declare const userPrimaryAssistantVar: import("./persistent-vars").Persis
68
68
  export declare const groupPrimaryAssistantVar: import("./persistent-vars").PersistentVar<string | undefined>;
69
69
  export declare const getPrimaryAssistant: (dataContext?: DataContext) => Promise<{
70
70
  name: string;
71
- createdAt: Date;
72
71
  assistantId: string;
72
+ createdAt: Date;
73
73
  assistantRunnerToolId: string;
74
74
  assistantRunnerConfig: {} & {
75
75
  [k: string]: any;
@@ -20,7 +20,7 @@ export declare const channelSchema: z.ZodObject<{
20
20
  owningGroupId: string;
21
21
  }>;
22
22
  export type IChannel = z.infer<typeof channelSchema>;
23
- export declare function Channels(dataContext?: DataContext): import("./orm").Table<{
23
+ export declare function Channels(dataContext?: DataContext): import("..").Table<{
24
24
  name: string;
25
25
  description: string;
26
26
  createdAt: Date;
@@ -38,7 +38,7 @@ export interface IDeviceHandshake extends IDeviceInfo {
38
38
  serverAddress: string;
39
39
  timestamp: number;
40
40
  }
41
- export declare function Devices(dataContext?: DataContext): import("./orm").Table<{
41
+ export declare function Devices(dataContext?: DataContext): import("..").Table<{
42
42
  userId: string;
43
43
  deviceId: string;
44
44
  firstSeen: Date;
@@ -34,7 +34,7 @@ export declare const embeddingSchema: z.ZodObject<{
34
34
  embeddingType: string;
35
35
  }>;
36
36
  export type IEmbedding = z.infer<typeof embeddingSchema>;
37
- export declare function Embeddings(dataContext?: DataContext): import("./orm").Table<{
37
+ export declare function Embeddings(dataContext?: DataContext): import("..").Table<{
38
38
  metadata: {
39
39
  fkId?: string | undefined;
40
40
  } & {
@@ -0,0 +1,21 @@
1
+ import type { DataContext } from "../context/data-context";
2
+ import { type IPublicKeys, type IPublicPrivateKeys } from "../keys";
3
+ import { type IPersistentVar } from "./persistent-vars";
4
+ /** Prefix used for each group's encrypted secret-key persistent variable. */
5
+ export declare const GROUP_SECRET_KEY_PVAR_PREFIX = "groupSecretKey_";
6
+ /** Return the personal-context persistent-variable name for a group secret key. */
7
+ export declare function groupSecretKeyPvarName(groupId: string): string;
8
+ /**
9
+ * Derive a group secret's public keys and verify they match the signed group record.
10
+ *
11
+ * @throws When the secret is malformed or derives different signing/box public keys.
12
+ */
13
+ export declare function validateGroupSecretKey(secretKey: string, expected: IPublicKeys): IPublicPrivateKeys;
14
+ /**
15
+ * Save a known-valid group secret in the user's personal context.
16
+ *
17
+ * Legacy random IDs and duplicate name rows are canonicalized before the replacement is
18
+ * encrypted and saved. The caller must supply the expected signed group public keys, so this
19
+ * function cannot silently install unrelated key material.
20
+ */
21
+ export declare function saveGroupSecretKey(userDataContext: DataContext, groupId: string, secretKey: string, expected: IPublicKeys): Promise<IPersistentVar>;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GROUP_SECRET_KEY_PVAR_PREFIX = void 0;
4
+ exports.groupSecretKeyPvarName = groupSecretKeyPvarName;
5
+ exports.validateGroupSecretKey = validateGroupSecretKey;
6
+ exports.saveGroupSecretKey = saveGroupSecretKey;
7
+ const keys_1 = require("../keys");
8
+ const utils_1 = require("../utils");
9
+ const persistent_vars_1 = require("./persistent-vars");
10
+ /** Prefix used for each group's encrypted secret-key persistent variable. */
11
+ exports.GROUP_SECRET_KEY_PVAR_PREFIX = "groupSecretKey_";
12
+ /** Return the personal-context persistent-variable name for a group secret key. */
13
+ function groupSecretKeyPvarName(groupId) {
14
+ return `${exports.GROUP_SECRET_KEY_PVAR_PREFIX}${groupId}`;
15
+ }
16
+ /**
17
+ * Derive a group secret's public keys and verify they match the signed group record.
18
+ *
19
+ * @throws When the secret is malformed or derives different signing/box public keys.
20
+ */
21
+ function validateGroupSecretKey(secretKey, expected) {
22
+ const derived = (0, keys_1.hydrateKeys)(secretKey);
23
+ if (derived.publicKey !== expected.publicKey || derived.publicBoxKey !== expected.publicBoxKey) {
24
+ throw new Error("Group secret key does not match the group's public keys");
25
+ }
26
+ return derived;
27
+ }
28
+ /**
29
+ * Save a known-valid group secret in the user's personal context.
30
+ *
31
+ * Legacy random IDs and duplicate name rows are canonicalized before the replacement is
32
+ * encrypted and saved. The caller must supply the expected signed group public keys, so this
33
+ * function cannot silently install unrelated key material.
34
+ */
35
+ async function saveGroupSecretKey(userDataContext, groupId, secretKey, expected) {
36
+ validateGroupSecretKey(secretKey, expected);
37
+ const name = groupSecretKeyPvarName(groupId);
38
+ const table = (0, persistent_vars_1.PersistentVars)(userDataContext);
39
+ const records = await table.list({ name });
40
+ let canonical = records.find((record) => record.persistentVarId === (0, utils_1.deterministicPvarId)(name));
41
+ for (const record of records) {
42
+ if (record !== canonical) {
43
+ canonical = await table.migrateLegacyId(record);
44
+ }
45
+ }
46
+ return table.save({
47
+ persistentVarId: canonical?.persistentVarId ?? "",
48
+ name,
49
+ scope: "groupUser",
50
+ isSecret: true,
51
+ value: { value: secretKey },
52
+ });
53
+ }
@@ -8,6 +8,7 @@ export * from "./files";
8
8
  export * from "./group-member-roles";
9
9
  export * from "./group-members";
10
10
  export * from "./group-permissions";
11
+ export * from "./group-secret";
11
12
  export * from "./group-share";
12
13
  export * from "./groups";
13
14
  export * from "./messages";
@@ -24,6 +24,7 @@ __exportStar(require("./files"), exports);
24
24
  __exportStar(require("./group-member-roles"), exports);
25
25
  __exportStar(require("./group-members"), exports);
26
26
  __exportStar(require("./group-permissions"), exports);
27
+ __exportStar(require("./group-secret"), exports);
27
28
  __exportStar(require("./group-share"), exports);
28
29
  __exportStar(require("./groups"), exports);
29
30
  __exportStar(require("./messages"), exports);
@@ -35,7 +35,7 @@ export declare const messageSchema: z.ZodObject<{
35
35
  fileIds?: string[] | undefined;
36
36
  }>;
37
37
  export type IMessage = z.infer<typeof messageSchema>;
38
- export declare function Messages(dataContext?: DataContext): import("./orm").Table<{
38
+ export declare function Messages(dataContext?: DataContext): import("..").Table<{
39
39
  message: string;
40
40
  userId: string;
41
41
  createdAt: Date;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Return whether a table method was explicitly marked for remote invocation by
3
+ * {@link ProxyClientTableMethodCalls}. Client proxies are recognized through their
4
+ * marked `__original` implementation as well.
5
+ */
6
+ export declare function isContractRemoteTableMethod(method: unknown): boolean;
1
7
  /**
2
8
  * Decorator that marks a table method as server-side only.
3
9
  * When used on the client side, these methods will be automatically proxied
@@ -1,7 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isContractRemoteTableMethod = isContractRemoteTableMethod;
3
4
  exports.ProxyClientTableMethodCalls = ProxyClientTableMethodCalls;
4
5
  const rpc_types_1 = require("../../rpc-types");
6
+ const contractRemoteTableMethod = Symbol("contractRemoteTableMethod");
7
+ function markContractRemoteTableMethod(method) {
8
+ Object.defineProperty(method, contractRemoteTableMethod, { value: true });
9
+ }
10
+ /**
11
+ * Return whether a table method was explicitly marked for remote invocation by
12
+ * {@link ProxyClientTableMethodCalls}. Client proxies are recognized through their
13
+ * marked `__original` implementation as well.
14
+ */
15
+ function isContractRemoteTableMethod(method) {
16
+ if (typeof method !== "function") {
17
+ return false;
18
+ }
19
+ const candidate = method;
20
+ return Boolean(candidate[contractRemoteTableMethod] || candidate.__original?.[contractRemoteTableMethod]);
21
+ }
5
22
  /**
6
23
  * Decorator that marks a table method as server-side only.
7
24
  * When used on the client side, these methods will be automatically proxied
@@ -13,6 +30,9 @@ const rpc_types_1 = require("../../rpc-types");
13
30
  */
14
31
  function ProxyClientTableMethodCalls() {
15
32
  return (target, context) => {
33
+ if (context.kind === "method") {
34
+ markContractRemoteTableMethod(target);
35
+ }
16
36
  if (context.kind === "method" && rpc_types_1.isClient) {
17
37
  const methodName = context.name;
18
38
  // WARNING: Using typescript's magical `this` param
@@ -21,6 +41,7 @@ function ProxyClientTableMethodCalls() {
21
41
  return rpc_types_1.rpcServerCalls.tableMethodCall(dataContextId, this.tableName, methodName, ...args);
22
42
  };
23
43
  proxyFn.__original = target;
44
+ markContractRemoteTableMethod(proxyFn);
24
45
  return proxyFn;
25
46
  }
26
47
  return target;