@canonmsg/agent-sdk 12.0.0 → 12.1.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 (99) hide show
  1. package/README.md +97 -7
  2. package/dist/chunks/{chunk-FPQFTTND.js → chunk-7N6OPPW4.js} +1616 -1085
  3. package/dist/chunks/chunk-N722GWCP.js +4897 -0
  4. package/dist/chunks/{chunk-OLJ7H4E2.js → chunk-QZ4PPRQW.js} +6462 -6920
  5. package/dist/chunks/{mls-crypto-NZDNSPAO.js → mls-crypto-LMNQZOS6.js} +3 -3
  6. package/dist/cli.js +403 -29
  7. package/dist/drivers/claude.d.ts +8 -2
  8. package/dist/drivers/codex.d.ts +11 -2
  9. package/dist/drivers/connector.d.ts +34 -0
  10. package/dist/index.d.ts +10 -2
  11. package/dist/index.js +26 -4
  12. package/dist/internal/backend-contracts/artifactActions.d.ts +0 -151
  13. package/dist/internal/backend-contracts/clientFloor.d.ts +41 -0
  14. package/dist/internal/backend-contracts/communication.d.ts +15 -0
  15. package/dist/internal/backend-contracts/connectorRelay.d.ts +179 -0
  16. package/dist/internal/backend-contracts/endpoint.d.ts +17 -0
  17. package/dist/internal/backend-contracts/endpointContentPolicy.d.ts +15 -4
  18. package/dist/internal/backend-contracts/index.d.ts +7 -1
  19. package/dist/internal/backend-contracts/media-url.d.ts +14 -0
  20. package/dist/internal/backend-contracts/message.d.ts +1 -1
  21. package/dist/internal/backend-contracts/mlsDevApplication.d.ts +90 -2
  22. package/dist/internal/backend-contracts/mlsDevCredential.d.ts +5 -2
  23. package/dist/internal/backend-contracts/mlsDevDeviceCustody.d.ts +2 -1
  24. package/dist/internal/backend-contracts/mlsDevEnrollment.d.ts +3 -2
  25. package/dist/internal/backend-contracts/mlsDevFeedReceipt.d.ts +43 -0
  26. package/dist/internal/backend-contracts/mlsDevGroup.d.ts +129 -5
  27. package/dist/internal/backend-contracts/mlsDevGroupFeed.d.ts +6 -2
  28. package/dist/internal/backend-contracts/mlsDevInteraction.d.ts +159 -0
  29. package/dist/internal/backend-contracts/mlsEnvironment.d.ts +35 -0
  30. package/dist/internal/backend-contracts/mlsPrincipalAlias.d.ts +23 -0
  31. package/dist/internal/backend-contracts/runtimeCardFields.d.ts +2 -2
  32. package/dist/internal/backend-contracts/upload-mime-types.d.ts +17 -0
  33. package/dist/internal/backend-contracts/verbContract.d.ts +15 -7
  34. package/dist/internal/backend-contracts/verbSchemas.d.ts +35 -25
  35. package/dist/internal/core/agent-profiles.d.ts +0 -4
  36. package/dist/internal/core/approval-format.d.ts +1 -5
  37. package/dist/internal/core/approval-types.d.ts +1 -2
  38. package/dist/internal/core/client.d.ts +2 -56
  39. package/dist/internal/core/constants.d.ts +0 -3
  40. package/dist/internal/core/endpoint-client.d.ts +14 -1
  41. package/dist/internal/core/execution-environment-mode.d.ts +0 -2
  42. package/dist/internal/core/gifs.d.ts +0 -6
  43. package/dist/internal/core/host-runtime.d.ts +2 -206
  44. package/dist/internal/core/index.d.ts +21 -60
  45. package/dist/internal/core/registration.d.ts +1 -17
  46. package/dist/internal/core/retry.d.ts +0 -9
  47. package/dist/internal/core/rtdb-rest.d.ts +0 -4
  48. package/dist/internal/core/runtime-cards.d.ts +0 -45
  49. package/dist/internal/core/runtime-descriptor.d.ts +1 -60
  50. package/dist/internal/core/runtime-presentation.d.ts +1 -27
  51. package/dist/internal/core/runtime-request-manager.d.ts +0 -1
  52. package/dist/internal/core/self-context.d.ts +0 -39
  53. package/dist/internal/core/silent-turn.d.ts +1 -38
  54. package/dist/internal/core/stream.d.ts +2 -1
  55. package/dist/internal/core/turn-protocol.d.ts +0 -5
  56. package/dist/internal/core/turn-verbosity.d.ts +0 -12
  57. package/dist/internal/core/types.d.ts +0 -111
  58. package/dist/internal/endpoint/engine.d.ts +31 -1
  59. package/dist/internal/endpoint/index.d.ts +1 -1
  60. package/dist/internal/endpoint/media.d.ts +5 -0
  61. package/dist/internal/endpoint/mls-crypto.d.ts +12 -5
  62. package/dist/internal/endpoint/mls-dev-client.d.ts +9 -1
  63. package/dist/internal/endpoint/mls-dev-device.d.ts +2 -0
  64. package/dist/internal/endpoint/mls-dev-groups.d.ts +65 -5
  65. package/dist/internal/endpoint/mls-dev-interactions.d.ts +99 -0
  66. package/dist/internal/endpoint/mls-dev-key-package-service.d.ts +13 -0
  67. package/dist/internal/endpoint/mls-dev-key-packages.d.ts +23 -3
  68. package/dist/internal/endpoint/mls-dev-text.d.ts +67 -0
  69. package/dist/internal/endpoint/mls-dev-transport.d.ts +2 -1
  70. package/dist/internal/endpoint/node-mls-custody-protocol.d.ts +5 -0
  71. package/dist/internal/endpoint/transport.d.ts +6 -1
  72. package/dist/media.js +2 -2
  73. package/dist/runner/errands.d.ts +118 -0
  74. package/dist/runner/mls.d.ts +97 -0
  75. package/dist/runner/relay.d.ts +87 -0
  76. package/dist/runner/runner.d.ts +61 -0
  77. package/dist/runner/types.d.ts +51 -4
  78. package/package.json +1 -1
  79. package/dist/chunks/chunk-6VK4UZHJ.js +0 -2806
  80. package/dist/internal/backend-contracts/workSessions.d.ts +0 -205
  81. package/dist/internal/core/agent-resolver.d.ts +0 -49
  82. package/dist/internal/core/agent-session.d.ts +0 -12
  83. package/dist/internal/core/artifacts.d.ts +0 -262
  84. package/dist/internal/core/attached-native-session.d.ts +0 -174
  85. package/dist/internal/core/attached-session-file-store.d.ts +0 -3
  86. package/dist/internal/core/control-poller.d.ts +0 -221
  87. package/dist/internal/core/exclusive-json-file-store.d.ts +0 -7
  88. package/dist/internal/core/execution-environment.d.ts +0 -55
  89. package/dist/internal/core/group-context.d.ts +0 -25
  90. package/dist/internal/core/inbound-frame.d.ts +0 -64
  91. package/dist/internal/core/local-runtime-catalog.d.ts +0 -131
  92. package/dist/internal/core/message-format.d.ts +0 -13
  93. package/dist/internal/core/native-session-interaction.d.ts +0 -44
  94. package/dist/internal/core/provenance.d.ts +0 -31
  95. package/dist/internal/core/registration-cli.d.ts +0 -40
  96. package/dist/internal/core/turn-output-controller.d.ts +0 -69
  97. package/dist/internal/core/typing-status-publisher.d.ts +0 -14
  98. package/dist/internal/core/work-session-provider.d.ts +0 -29
  99. package/dist/internal/core/workspace-discovery.d.ts +0 -17
@@ -27,6 +27,22 @@ function getCanonEnvironmentContract(value) {
27
27
  }
28
28
  __name(getCanonEnvironmentContract, "getCanonEnvironmentContract");
29
29
 
30
+ // ../backend-contracts/src/clientFloor.ts
31
+ var CANON_CLIENT_HEADER = "X-Canon-Client";
32
+ var CLIENT_UPDATE_REQUIRED = "CLIENT_UPDATE_REQUIRED";
33
+ var CANON_CLIENT_KINDS = ["app-ios", "app-android", "web", "runner", "hermes", "core", "connector"];
34
+ var VERSION = /^(0|[1-9]\d{0,5})\.(0|[1-9]\d{0,5})\.(0|[1-9]\d{0,5})$/;
35
+ var isKind = /* @__PURE__ */ __name((value) => CANON_CLIENT_KINDS.includes(value), "isKind");
36
+ function isCanonClientVersion(value) {
37
+ return typeof value === "string" && VERSION.test(value);
38
+ }
39
+ __name(isCanonClientVersion, "isCanonClientVersion");
40
+ function formatCanonClientHeader(client) {
41
+ if (!isKind(client.kind) || !isCanonClientVersion(client.version)) throw new Error("Invalid Canon client identity");
42
+ return `${client.kind}/${client.version}`;
43
+ }
44
+ __name(formatCanonClientHeader, "formatCanonClientHeader");
45
+
30
46
  // ../backend-contracts/src/media.ts
31
47
  function sanitizeDownloadFileName(value, fallback = "attachment") {
32
48
  const baseName = typeof value === "string" ? value.trim().split(/[\\/]/).filter(Boolean).pop() ?? "" : "";
@@ -45,6 +61,193 @@ function sanitizeDownloadFileName(value, fallback = "attachment") {
45
61
  return `${safeStem.replace(/[. -]+$/g, "")}${extension}`;
46
62
  }
47
63
  __name(sanitizeDownloadFileName, "sanitizeDownloadFileName");
64
+ function describeAttachment(attachment) {
65
+ if (!attachment) return null;
66
+ if (attachment.kind === "image") return "\u{1F4F7} Image";
67
+ if (attachment.kind === "audio") return "\u{1F3A4} Voice message";
68
+ if (attachment.kind === "video") return "\u{1F3AC} Video";
69
+ return attachment.fileName ? `\u{1F4CE} ${attachment.fileName}` : "\u{1F4CE} File";
70
+ }
71
+ __name(describeAttachment, "describeAttachment");
72
+
73
+ // ../backend-contracts/src/media-origins.generated.ts
74
+ var MEDIA_ORIGINS = {
75
+ "canonmail-dev.firebasestorage.app": "https://dev.api.canonmail.com",
76
+ "canonmail-prod.firebasestorage.app": "https://api.canonmail.com"
77
+ };
78
+
79
+ // ../backend-contracts/src/media-url.ts
80
+ function validMediaPath(path) {
81
+ const parts = path.split("/");
82
+ return parts.length === 4 && parts[0] === "media" && parts.every((part) => Boolean(part) && part !== "." && part !== ".." && !/[\u0000-\u001f\u007f\\]/.test(part));
83
+ }
84
+ __name(validMediaPath, "validMediaPath");
85
+ function parseMediaStoragePath(value, bucket) {
86
+ if (typeof value !== "string") return null;
87
+ try {
88
+ const url = new URL(value);
89
+ if (url.protocol !== "https:" || url.username || url.password) return null;
90
+ let path;
91
+ const prefix = `/v0/b/${bucket}/o/`;
92
+ if (url.origin === "https://firebasestorage.googleapis.com" && url.pathname.startsWith(prefix)) {
93
+ path = decodeURIComponent(url.pathname.slice(prefix.length));
94
+ } else if (url.origin === MEDIA_ORIGINS[bucket] && url.pathname.startsWith("/files/")) {
95
+ path = `media/${decodeURIComponent(url.pathname.slice("/files/".length))}`;
96
+ } else return null;
97
+ return validMediaPath(path) ? path : null;
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ __name(parseMediaStoragePath, "parseMediaStoragePath");
103
+ function isCanonMediaOrigin(url) {
104
+ try {
105
+ return Object.values(MEDIA_ORIGINS).includes(new URL(url).origin);
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+ __name(isCanonMediaOrigin, "isCanonMediaOrigin");
111
+ function isCanonUploadUrl(url, input) {
112
+ try {
113
+ const bucket = `${getCanonEnvironmentContract(input.environmentId).projectId}.firebasestorage.app`;
114
+ const parsed = new URL(url);
115
+ if (parsed.origin !== MEDIA_ORIGINS[bucket] || parsed.hash || [...parsed.searchParams.keys()].join() !== "token" || !parsed.searchParams.get("token")) return false;
116
+ const path = parseMediaStoragePath(url, bucket);
117
+ const [, conversationId, , file] = path?.split("/") ?? [];
118
+ const expected = input.poster ? `resumable-${input.uploadId}-poster.jpg` : null;
119
+ return conversationId === input.conversationId && (expected ? file === expected : !!file && file.startsWith(`resumable-${input.uploadId}.`) && /^[a-z0-9]{1,8}$/.test(file.slice(`resumable-${input.uploadId}.`.length)));
120
+ } catch {
121
+ return false;
122
+ }
123
+ }
124
+ __name(isCanonUploadUrl, "isCanonUploadUrl");
125
+
126
+ // ../backend-contracts/src/upload-mime-types.ts
127
+ var MIME_TYPE_RE = /^[a-z0-9.+-]+\/[a-z0-9.+-]+$/i;
128
+ var SAFE_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
129
+ "image/jpeg",
130
+ "image/png",
131
+ "image/webp",
132
+ "image/gif"
133
+ ]);
134
+ var SAFE_AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
135
+ "audio/mp4",
136
+ "audio/x-m4a",
137
+ "audio/mpeg",
138
+ "audio/webm",
139
+ "audio/ogg",
140
+ "audio/wav",
141
+ // ADTS AAC — the future Android streamable-memo lane; harmless standalone.
142
+ "audio/aac"
143
+ ]);
144
+ var SAFE_VIDEO_MIME_TYPES = /* @__PURE__ */ new Set([
145
+ "video/mp4",
146
+ "video/quicktime",
147
+ "video/webm",
148
+ "video/x-m4v"
149
+ ]);
150
+ var SAFE_FILE_MIME_TYPES = /* @__PURE__ */ new Set([
151
+ "application/pdf",
152
+ "text/plain",
153
+ "text/markdown",
154
+ "text/x-markdown",
155
+ "text/csv",
156
+ "application/csv",
157
+ "application/json",
158
+ "application/zip",
159
+ "application/vnd.ms-excel",
160
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
161
+ ]);
162
+ var SAFE_FILE_MIME_BY_EXTENSION = {
163
+ csv: "text/csv",
164
+ json: "application/json",
165
+ md: "text/markdown",
166
+ markdown: "text/markdown",
167
+ pdf: "application/pdf",
168
+ txt: "text/plain",
169
+ xls: "application/vnd.ms-excel",
170
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
171
+ zip: "application/zip"
172
+ };
173
+ var SAFE_VIDEO_MIME_BY_EXTENSION = {
174
+ m4v: "video/x-m4v",
175
+ mov: "video/quicktime",
176
+ mp4: "video/mp4",
177
+ webm: "video/webm"
178
+ };
179
+ var SAFE_AUDIO_MIME_BY_EXTENSION = {
180
+ aac: "audio/aac",
181
+ m4a: "audio/x-m4a",
182
+ mp3: "audio/mpeg",
183
+ oga: "audio/ogg",
184
+ ogg: "audio/ogg",
185
+ wav: "audio/wav"
186
+ };
187
+ function normalizeMimeType(value) {
188
+ if (typeof value !== "string") return null;
189
+ const normalized = value.split(";")[0].trim().toLowerCase();
190
+ if (!MIME_TYPE_RE.test(normalized)) return null;
191
+ if (normalized === "image/jpg") return "image/jpeg";
192
+ return normalized;
193
+ }
194
+ __name(normalizeMimeType, "normalizeMimeType");
195
+ function inferSafeFileMimeTypeFromName(value) {
196
+ if (typeof value !== "string") return null;
197
+ const extension = value.trim().split(/[\\/]/).pop()?.split(".").pop()?.toLowerCase() ?? "";
198
+ return SAFE_FILE_MIME_BY_EXTENSION[extension] ?? null;
199
+ }
200
+ __name(inferSafeFileMimeTypeFromName, "inferSafeFileMimeTypeFromName");
201
+ function inferSafeVideoMimeTypeFromName(value) {
202
+ if (typeof value !== "string") return null;
203
+ const extension = value.trim().split(/[\\/]/).pop()?.split(".").pop()?.toLowerCase() ?? "";
204
+ return SAFE_VIDEO_MIME_BY_EXTENSION[extension] ?? null;
205
+ }
206
+ __name(inferSafeVideoMimeTypeFromName, "inferSafeVideoMimeTypeFromName");
207
+ function inferSafeAudioMimeTypeFromName(value) {
208
+ if (typeof value !== "string") return null;
209
+ const extension = value.trim().split(/[\\/]/).pop()?.split(".").pop()?.toLowerCase() ?? "";
210
+ return SAFE_AUDIO_MIME_BY_EXTENSION[extension] ?? null;
211
+ }
212
+ __name(inferSafeAudioMimeTypeFromName, "inferSafeAudioMimeTypeFromName");
213
+ function shouldTrustSafeFileName(mimeType) {
214
+ return !mimeType || mimeType === "application/octet-stream" || mimeType === "application/vnd.ms-excel" || mimeType === "text/plain";
215
+ }
216
+ __name(shouldTrustSafeFileName, "shouldTrustSafeFileName");
217
+ function classifyAllowedUploadMimeType(value) {
218
+ const mimeType = normalizeMimeType(value);
219
+ if (!mimeType) return null;
220
+ if (SAFE_IMAGE_MIME_TYPES.has(mimeType)) return "image";
221
+ if (SAFE_AUDIO_MIME_TYPES.has(mimeType)) return "audio";
222
+ if (SAFE_VIDEO_MIME_TYPES.has(mimeType)) return "video";
223
+ if (SAFE_FILE_MIME_TYPES.has(mimeType)) return "file";
224
+ return null;
225
+ }
226
+ __name(classifyAllowedUploadMimeType, "classifyAllowedUploadMimeType");
227
+ function resolveAllowedUploadMimeType(input) {
228
+ const normalizedMimeType = normalizeMimeType(input.mimeType);
229
+ const hasExplicitMimeType = typeof input.mimeType === "string" && input.mimeType.trim().length > 0;
230
+ const inferredVideoMimeType = inferSafeVideoMimeTypeFromName(input.fileName);
231
+ const inferredAudioMimeType = inferSafeAudioMimeTypeFromName(input.fileName);
232
+ const inferredFileMimeType = inferSafeFileMimeTypeFromName(input.fileName);
233
+ if (hasExplicitMimeType && !normalizedMimeType) {
234
+ return null;
235
+ }
236
+ if (inferredVideoMimeType && (!normalizedMimeType || normalizedMimeType === "application/octet-stream")) {
237
+ return inferredVideoMimeType;
238
+ }
239
+ if (inferredAudioMimeType && (!normalizedMimeType || normalizedMimeType === "application/octet-stream")) {
240
+ return inferredAudioMimeType;
241
+ }
242
+ if (inferredFileMimeType && shouldTrustSafeFileName(normalizedMimeType)) {
243
+ return inferredFileMimeType;
244
+ }
245
+ if (normalizedMimeType && classifyAllowedUploadMimeType(normalizedMimeType)) {
246
+ return normalizedMimeType;
247
+ }
248
+ return normalizedMimeType ? null : inferredFileMimeType;
249
+ }
250
+ __name(resolveAllowedUploadMimeType, "resolveAllowedUploadMimeType");
48
251
 
49
252
  // ../backend-contracts/src/mlsDevValidation.ts
50
253
  function invalid() {
@@ -57,14 +260,14 @@ function readMlsDataRecord(value, keys2, alternateKeys) {
57
260
  if (prototype !== Object.prototype && prototype !== null) invalid();
58
261
  const descriptors = Object.getOwnPropertyDescriptors(value);
59
262
  const ownKeys = Reflect.ownKeys(descriptors);
60
- const shape = [keys2, ...alternateKeys ? [alternateKeys] : []].find((candidate) => ownKeys.length === candidate.length && ownKeys.every((key2) => typeof key2 === "string" && candidate.includes(key2)));
263
+ const shape = [keys2, ...alternateKeys ? [alternateKeys] : []].find((candidate) => ownKeys.length === candidate.length && ownKeys.every((key) => typeof key === "string" && candidate.includes(key)));
61
264
  if (!shape) invalid();
62
265
  const snapshot = /* @__PURE__ */ Object.create(null);
63
- for (const key2 of ownKeys) {
64
- if (typeof key2 !== "string") invalid();
65
- const descriptor = descriptors[key2];
266
+ for (const key of ownKeys) {
267
+ if (typeof key !== "string") invalid();
268
+ const descriptor = descriptors[key];
66
269
  if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) invalid();
67
- snapshot[key2] = descriptor.value;
270
+ snapshot[key] = descriptor.value;
68
271
  }
69
272
  return snapshot;
70
273
  }
@@ -85,6 +288,51 @@ function requireMlsUuid(value) {
85
288
  }
86
289
  __name(requireMlsUuid, "requireMlsUuid");
87
290
 
291
+ // ../backend-contracts/src/mlsEnvironment.ts
292
+ var MLS_ENVIRONMENT_PROFILES = Object.freeze({
293
+ "canon-dev-v1": Object.freeze({
294
+ issuer: "canon-mls-dev-v1",
295
+ credentialType: "canon-mls-dev-credential+jws",
296
+ issuerKeyPath: "projects/canonmail-dev/locations/europe-west1/keyRings/canon-mls/cryptoKeys/device-issuer",
297
+ receiptKeyPath: "projects/canonmail-dev/locations/europe-west1/keyRings/canon-mls/cryptoKeys/feed-receipt"
298
+ }),
299
+ "canon-prod-v1": Object.freeze({
300
+ issuer: "canon-mls-prod-v1",
301
+ credentialType: "canon-mls-prod-credential+jws",
302
+ issuerKeyPath: "projects/canonmail-prod/locations/europe-west1/keyRings/canon-mls/cryptoKeys/device-issuer",
303
+ receiptKeyPath: "projects/canonmail-prod/locations/europe-west1/keyRings/canon-mls/cryptoKeys/feed-receipt"
304
+ })
305
+ });
306
+ function requireMlsEnvironmentId(value) {
307
+ if (!isMlsEnvironmentId(value)) throw new Error("INVALID_MLS_DATA");
308
+ return value;
309
+ }
310
+ __name(requireMlsEnvironmentId, "requireMlsEnvironmentId");
311
+ function isMlsEnvironmentId(value) {
312
+ return typeof value === "string" && Object.hasOwn(MLS_ENVIRONMENT_PROFILES, value);
313
+ }
314
+ __name(isMlsEnvironmentId, "isMlsEnvironmentId");
315
+ function mlsEnvironmentProfile(environmentId) {
316
+ return MLS_ENVIRONMENT_PROFILES[environmentId];
317
+ }
318
+ __name(mlsEnvironmentProfile, "mlsEnvironmentProfile");
319
+ function mlsEnvironmentOfIssuerKeyVersion(value) {
320
+ return environmentOfKeyVersion(value, "issuerKeyPath");
321
+ }
322
+ __name(mlsEnvironmentOfIssuerKeyVersion, "mlsEnvironmentOfIssuerKeyVersion");
323
+ function mlsEnvironmentOfReceiptKeyVersion(value) {
324
+ return environmentOfKeyVersion(value, "receiptKeyPath");
325
+ }
326
+ __name(mlsEnvironmentOfReceiptKeyVersion, "mlsEnvironmentOfReceiptKeyVersion");
327
+ function environmentOfKeyVersion(value, key) {
328
+ for (const [environmentId, profile] of Object.entries(MLS_ENVIRONMENT_PROFILES)) {
329
+ const prefix = profile[key] + "/cryptoKeyVersions/";
330
+ if (value.startsWith(prefix) && /^[1-9][0-9]{0,9}$/.test(value.slice(prefix.length))) return environmentId;
331
+ }
332
+ return void 0;
333
+ }
334
+ __name(environmentOfKeyVersion, "environmentOfKeyVersion");
335
+
88
336
  // ../backend-contracts/src/mlsDevEnrollment.ts
89
337
  var MLS_DEV_ENROLLMENT_CHALLENGE_TTL_MS = 3e5;
90
338
  var MLS_DEV_ENROLLMENT_MAX_BYTES = 4096;
@@ -209,7 +457,7 @@ function parseMlsDevEnrollmentChallenge(value) {
209
457
  version: requireMlsLiteral(input.version, 1),
210
458
  challengeId: requireMlsUuid(input.challengeId),
211
459
  deviceId: requireMlsUuid(input.deviceId),
212
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
460
+ environmentId: requireMlsEnvironmentId(input.environmentId),
213
461
  principal: principal(input.principal),
214
462
  installationId: installation(input.installationId),
215
463
  ciphersuite: requireMlsLiteral(input.ciphersuite, 1),
@@ -242,7 +490,7 @@ function parseMlsDevEnrollmentResult(value) {
242
490
  device: Object.freeze({
243
491
  version: requireMlsLiteral(device.version, 1),
244
492
  deviceId: requireMlsUuid(device.deviceId),
245
- environmentId: requireMlsLiteral(device.environmentId, "canon-dev-v1"),
493
+ environmentId: requireMlsEnvironmentId(device.environmentId),
246
494
  principal: principal(device.principal),
247
495
  installationId: installation(device.installationId),
248
496
  ciphersuite: requireMlsLiteral(device.ciphersuite, 1),
@@ -333,11 +581,11 @@ function encoded2(value, bytes) {
333
581
  return value;
334
582
  }
335
583
  __name(encoded2, "encoded");
336
- function parseMlsDevIssuerKeyVersion(value) {
584
+ function parseMlsDevIssuerKeyVersion(value, environmentId) {
337
585
  return boundary2(() => {
338
586
  if (typeof value !== "string" || value.length > 200) invalid3();
339
- const match = /^projects\/canonmail-dev\/locations\/europe-west1\/keyRings\/canon-mls\/cryptoKeys\/device-issuer\/cryptoKeyVersions\/[1-9][0-9]{0,9}$/.exec(value);
340
- if (!match || match[0] !== value) invalid3();
587
+ const owner = mlsEnvironmentOfIssuerKeyVersion(value);
588
+ if (!owner || environmentId !== void 0 && owner !== environmentId) invalid3();
341
589
  return value;
342
590
  });
343
591
  }
@@ -348,11 +596,12 @@ function parseMlsDevCredentialClaims(value) {
348
596
  const issuedAtMs = requireMlsInteger(input.issuedAtMs);
349
597
  const expiresAtMs = requireMlsInteger(input.expiresAtMs);
350
598
  if (expiresAtMs - issuedAtMs !== MLS_DEV_CREDENTIAL_TTL_MS) invalid3();
599
+ const device = parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: input.device }).device;
351
600
  return bounded2({
352
601
  version: requireMlsLiteral(input.version, 1),
353
602
  credentialId: requireMlsUuid(input.credentialId),
354
- issuer: requireMlsLiteral(input.issuer, "canon-mls-dev-v1"),
355
- device: parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: input.device }).device,
603
+ issuer: requireMlsLiteral(input.issuer, mlsEnvironmentProfile(device.environmentId).issuer),
604
+ device,
356
605
  generation: requireMlsInteger(input.generation, 1),
357
606
  issuedAtMs,
358
607
  expiresAtMs
@@ -363,7 +612,9 @@ __name(parseMlsDevCredentialClaims, "parseMlsDevCredentialClaims");
363
612
  function parseMlsDevCredentialUnsigned(value) {
364
613
  return boundary2(() => {
365
614
  const input = readMlsDataRecord(value, ["keyVersion", "claims"]);
366
- return bounded2({ keyVersion: parseMlsDevIssuerKeyVersion(input.keyVersion), claims: parseMlsDevCredentialClaims(input.claims) });
615
+ const keyVersion = parseMlsDevIssuerKeyVersion(input.keyVersion), claims = parseMlsDevCredentialClaims(input.claims);
616
+ if (mlsEnvironmentOfIssuerKeyVersion(keyVersion) !== claims.device.environmentId) invalid3();
617
+ return bounded2({ keyVersion, claims });
367
618
  });
368
619
  }
369
620
  __name(parseMlsDevCredentialUnsigned, "parseMlsDevCredentialUnsigned");
@@ -423,7 +674,7 @@ function parseMlsDevCredentialRevocationReceipt(value) {
423
674
  }
424
675
  __name(parseMlsDevCredentialRevocationReceipt, "parseMlsDevCredentialRevocationReceipt");
425
676
  function signingInput(unsigned2) {
426
- const header = { alg: "Ed25519", typ: "canon-mls-dev-credential+jws", kid: unsigned2.keyVersion };
677
+ const header = { alg: "Ed25519", typ: mlsEnvironmentProfile(unsigned2.claims.device.environmentId).credentialType, kid: unsigned2.keyVersion };
427
678
  const result = encodeCanonicalMlsBase64Url(utf82.encode(JSON.stringify(header))) + "." + encodeCanonicalMlsBase64Url(utf82.encode(JSON.stringify(unsigned2.claims)));
428
679
  if (result.length > MLS_DEV_CREDENTIAL_MAX_BYTES) invalid3();
429
680
  return result;
@@ -445,8 +696,8 @@ function parseMlsDevCredentialSigningInput(value) {
445
696
  if (parts.length !== 2) invalid3();
446
697
  const header = readMlsDataRecord(jsonSegment(parts[0]), ["alg", "typ", "kid"]);
447
698
  requireMlsLiteral(header.alg, "Ed25519");
448
- requireMlsLiteral(header.typ, "canon-mls-dev-credential+jws");
449
699
  const unsigned2 = parseMlsDevCredentialUnsigned({ keyVersion: header.kid, claims: jsonSegment(parts[1]) });
700
+ requireMlsLiteral(header.typ, mlsEnvironmentProfile(unsigned2.claims.device.environmentId).credentialType);
450
701
  if (signingInput(unsigned2) !== value) invalid3();
451
702
  return unsigned2;
452
703
  });
@@ -476,6 +727,54 @@ function parseMlsDevCredentialReceipt(value) {
476
727
  }
477
728
  __name(parseMlsDevCredentialReceipt, "parseMlsDevCredentialReceipt");
478
729
 
730
+ // ../backend-contracts/src/mlsDevFeedReceipt.ts
731
+ var MlsDevFeedReceiptValidationError = class extends Error {
732
+ static {
733
+ __name(this, "MlsDevFeedReceiptValidationError");
734
+ }
735
+ code = "INVALID_MLS_DEV_FEED_RECEIPT";
736
+ constructor() {
737
+ super("INVALID_MLS_DEV_FEED_RECEIPT");
738
+ this.name = "MlsDevFeedReceiptValidationError";
739
+ }
740
+ };
741
+ function invalid4() {
742
+ throw new MlsDevFeedReceiptValidationError();
743
+ }
744
+ __name(invalid4, "invalid");
745
+ function boundary3(read) {
746
+ try {
747
+ return read();
748
+ } catch {
749
+ return invalid4();
750
+ }
751
+ }
752
+ __name(boundary3, "boundary");
753
+ function parseMlsDevReceiptKeyVersion(value, environmentId) {
754
+ return boundary3(() => {
755
+ if (typeof value !== "string" || value.length > 200) invalid4();
756
+ const owner = mlsEnvironmentOfReceiptKeyVersion(value);
757
+ if (!owner || environmentId !== void 0 && owner !== environmentId) invalid4();
758
+ return value;
759
+ });
760
+ }
761
+ __name(parseMlsDevReceiptKeyVersion, "parseMlsDevReceiptKeyVersion");
762
+ function parseMlsDevFeedReceiptProof(value) {
763
+ return boundary3(() => {
764
+ const input = readMlsDataRecord(value, ["keyVersion", "signature"]);
765
+ decodeCanonicalMlsBase64Url(input.signature, 64);
766
+ return Object.freeze({ keyVersion: parseMlsDevReceiptKeyVersion(input.keyVersion), signature: input.signature });
767
+ });
768
+ }
769
+ __name(parseMlsDevFeedReceiptProof, "parseMlsDevFeedReceiptProof");
770
+ var MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW = "MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW";
771
+ function isMlsDevReceiptClockSkew(value) {
772
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
773
+ const keys2 = Object.keys(value).sort().join(), input = value;
774
+ return (keys2 === "error,ok,retryable" || keys2 === "error,ok,retryable,version" && input.version === 1) && input.ok === false && input.error === MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW && input.retryable === true;
775
+ }
776
+ __name(isMlsDevReceiptClockSkew, "isMlsDevReceiptClockSkew");
777
+
479
778
  // ../backend-contracts/src/mlsDevGroupFeed.ts
480
779
  var MLS_DEV_GROUP_FEED_MAX_ENTRIES = 4;
481
780
  var MLS_DEV_GROUP_FEED_MAX_BYTES = 4 * 1024 * 1024;
@@ -489,99 +788,104 @@ var MlsDevGroupFeedValidationError = class extends Error {
489
788
  this.name = "MlsDevGroupFeedValidationError";
490
789
  }
491
790
  };
492
- function invalid4() {
791
+ function invalid5() {
493
792
  throw new MlsDevGroupFeedValidationError();
494
793
  }
495
- __name(invalid4, "invalid");
496
- function boundary3(read) {
794
+ __name(invalid5, "invalid");
795
+ function boundary4(read) {
497
796
  try {
498
797
  return read();
499
798
  } catch {
500
- return invalid4();
799
+ return invalid5();
501
800
  }
502
801
  }
503
- __name(boundary3, "boundary");
802
+ __name(boundary4, "boundary");
504
803
  function id(value) {
505
804
  if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..")
506
- invalid4();
805
+ invalid5();
507
806
  return value;
508
807
  }
509
808
  __name(id, "id");
510
809
  function boolean(value) {
511
810
  if (typeof value !== "boolean")
512
- invalid4();
811
+ invalid5();
513
812
  return value;
514
813
  }
515
814
  __name(boolean, "boolean");
516
815
  function bounded3(value) {
517
816
  if (new TextEncoder().encode(JSON.stringify(value)).length > MLS_DEV_GROUP_FEED_MAX_BYTES)
518
- invalid4();
817
+ invalid5();
519
818
  return Object.freeze(value);
520
819
  }
521
820
  __name(bounded3, "bounded");
522
821
  function array(value) {
523
822
  if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > MLS_DEV_GROUP_FEED_MAX_ENTRIES)
524
- invalid4();
823
+ invalid5();
525
824
  const descriptors = Object.getOwnPropertyDescriptors(value);
526
825
  if (Reflect.ownKeys(descriptors).length !== value.length + 1)
527
- invalid4();
826
+ invalid5();
528
827
  return Array.from({ length: value.length }, (_, index) => {
529
828
  const field = descriptors[index];
530
829
  if (!field || !field.enumerable || !Object.hasOwn(field, "value"))
531
- invalid4();
830
+ invalid5();
532
831
  return field.value;
533
832
  });
534
833
  }
535
834
  __name(array, "array");
536
835
  function parseMlsDevGroupFeedEntry(value) {
537
- return boundary3(() => {
538
- const input = readMlsDataRecord(value, ["version", "ordinal", "kind", "accepted"], ["version", "ordinal", "kind", "receipt", "envelope"]);
836
+ return boundary4(() => {
837
+ const signed = value !== null && typeof value === "object" && Object.hasOwn(value, "receiptProof") ? ["receiptProof"] : [];
838
+ const input = readMlsDataRecord(value, ["version", "ordinal", "kind", "accepted", ...signed], ["version", "ordinal", "kind", "receipt", "envelope", ...signed]);
539
839
  const version = requireMlsLiteral(input.version, 1), ordinal = requireMlsInteger(input.ordinal, 1);
840
+ const proof = signed.length ? { receiptProof: parseMlsDevFeedReceiptProof(input.receiptProof) } : {};
540
841
  if (input.kind === "control") {
541
842
  if (!Object.hasOwn(input, "accepted"))
542
- invalid4();
543
- return bounded3({ version, ordinal, kind: "control", accepted: parseMlsDevGroupAcceptedControl(input.accepted) });
843
+ invalid5();
844
+ return bounded3({ version, ordinal, kind: "control", accepted: parseMlsDevGroupAcceptedControl(input.accepted), ...proof });
544
845
  }
545
846
  const kind = requireMlsLiteral(input.kind, "application"), receipt = parseMlsDevApplicationReceipt(input.receipt), envelope = parseMlsDevApplicationEnvelope(input.envelope);
546
847
  if (ordinal !== receipt.feedOrdinal || receipt.conversationId !== envelope.conversationId || receipt.groupId !== envelope.groupId || receipt.messageId !== envelope.messageId || JSON.stringify(receipt.head) !== JSON.stringify(envelope.expectedHead))
547
- invalid4();
548
- return bounded3({ version, ordinal, kind, receipt, envelope });
848
+ invalid5();
849
+ return bounded3({ version, ordinal, kind, receipt, envelope, ...proof });
549
850
  });
550
851
  }
551
852
  __name(parseMlsDevGroupFeedEntry, "parseMlsDevGroupFeedEntry");
552
853
  function parseMlsDevGroupFeedQuery(value) {
553
- return boundary3(() => {
854
+ return boundary4(() => {
554
855
  const input = readMlsDataRecord(value, ["version", "conversationId", "credential", "afterOrdinal", "limit"]);
555
- const limit = requireMlsInteger(input.limit, 1);
556
- if (limit > MLS_DEV_GROUP_FEED_MAX_ENTRIES)
557
- invalid4();
856
+ const limit2 = requireMlsInteger(input.limit, 1);
857
+ if (limit2 > MLS_DEV_GROUP_FEED_MAX_ENTRIES)
858
+ invalid5();
558
859
  parseMlsDevCredentialToken(input.credential);
559
- return Object.freeze({ version: requireMlsLiteral(input.version, 1), conversationId: id(input.conversationId), credential: input.credential, afterOrdinal: requireMlsInteger(input.afterOrdinal), limit });
860
+ return Object.freeze({ version: requireMlsLiteral(input.version, 1), conversationId: id(input.conversationId), credential: input.credential, afterOrdinal: requireMlsInteger(input.afterOrdinal), limit: limit2 });
560
861
  });
561
862
  }
562
863
  __name(parseMlsDevGroupFeedQuery, "parseMlsDevGroupFeedQuery");
563
864
  function parseMlsDevGroupFeedResult(value) {
564
- return boundary3(() => {
865
+ return boundary4(() => {
565
866
  const input = readMlsDataRecord(value, ["version", "protocol", "conversationId", "marker", "membershipRevision", "admissionId", "roster", "minimumOrdinal", "latestOrdinal", "nextOrdinal", "entries", "hasMore", "terminal"]);
566
867
  const conversationId = id(input.conversationId), marker = input.marker === null ? null : parseMlsDevGroupMarker(input.marker);
567
868
  const minimumOrdinal = input.minimumOrdinal === null ? null : requireMlsInteger(input.minimumOrdinal, 1);
568
869
  const latestOrdinal = requireMlsInteger(input.latestOrdinal), nextOrdinal = requireMlsInteger(input.nextOrdinal);
569
870
  const entries = array(input.entries).map(parseMlsDevGroupFeedEntry), hasMore = boolean(input.hasMore), terminal = boolean(input.terminal);
570
871
  if (nextOrdinal > latestOrdinal || minimumOrdinal !== null && minimumOrdinal > latestOrdinal || minimumOrdinal === null && (entries.length || nextOrdinal || hasMore || terminal) || !marker && (latestOrdinal || minimumOrdinal !== null || entries.length || terminal))
571
- invalid4();
872
+ invalid5();
873
+ const protocol = isMlsDevTextProtocol(input.protocol) ? input.protocol : invalid5();
572
874
  for (let i = 0; i < entries.length; i++) {
573
875
  const entry = entries[i], subject = entry.kind === "control" ? entry.accepted.control : entry.envelope;
876
+ if (entry.kind === "application" && entry.envelope.interaction && !mlsDevProtocolCarriesCards(protocol))
877
+ invalid5();
574
878
  if (!marker || minimumOrdinal === null || entry.ordinal < minimumOrdinal || entry.ordinal > latestOrdinal || subject.conversationId !== conversationId || subject.groupId !== marker.groupId || i > 0 && entry.ordinal !== entries[i - 1].ordinal + 1)
575
- invalid4();
879
+ invalid5();
576
880
  const head = entry.kind === "control" ? entry.accepted.head : entry.receipt.head;
577
881
  if (head.sequence > marker.head.sequence || head.epoch > marker.head.epoch)
578
- invalid4();
882
+ invalid5();
579
883
  }
580
884
  if (entries.length && entries.at(-1).ordinal !== nextOrdinal || hasMore !== (minimumOrdinal !== null && nextOrdinal < latestOrdinal))
581
- invalid4();
885
+ invalid5();
582
886
  return bounded3({
583
887
  version: requireMlsLiteral(input.version, 1),
584
- protocol: requireMlsLiteral(input.protocol, MLS_DEV_TEXT_PROTOCOL),
888
+ protocol,
585
889
  conversationId,
586
890
  marker,
587
891
  membershipRevision: requireMlsInteger(input.membershipRevision),
@@ -611,25 +915,25 @@ var MlsDevKeyPackagesValidationError = class extends Error {
611
915
  this.name = "MlsDevKeyPackagesValidationError";
612
916
  }
613
917
  };
614
- function invalid5() {
918
+ function invalid6() {
615
919
  throw new MlsDevKeyPackagesValidationError();
616
920
  }
617
- __name(invalid5, "invalid");
618
- function boundary4(read) {
921
+ __name(invalid6, "invalid");
922
+ function boundary5(read) {
619
923
  try {
620
924
  return read();
621
925
  } catch {
622
- return invalid5();
926
+ return invalid6();
623
927
  }
624
928
  }
625
- __name(boundary4, "boundary");
929
+ __name(boundary5, "boundary");
626
930
  function bounded4(value) {
627
- if (new TextEncoder().encode(JSON.stringify(value)).length > MLS_DEV_KEY_PACKAGES_MAX_BYTES) invalid5();
931
+ if (new TextEncoder().encode(JSON.stringify(value)).length > MLS_DEV_KEY_PACKAGES_MAX_BYTES) invalid6();
628
932
  return Object.freeze(value);
629
933
  }
630
934
  __name(bounded4, "bounded");
631
935
  function id2(value) {
632
- if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..") invalid5();
936
+ if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..") invalid6();
633
937
  return value;
634
938
  }
635
939
  __name(id2, "id");
@@ -639,18 +943,18 @@ function ref(value) {
639
943
  }
640
944
  __name(ref, "ref");
641
945
  function parseMlsDevKeyPackageWire(value) {
642
- return boundary4(() => {
643
- if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_KEY_PACKAGE_TLS_MAX_BYTES * 4 / 3)) invalid5();
946
+ return boundary5(() => {
947
+ if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_KEY_PACKAGE_TLS_MAX_BYTES * 4 / 3)) invalid6();
644
948
  const bytes = Math.floor(value.length * 3 / 4);
645
- if (bytes < 1 || bytes > MLS_DEV_KEY_PACKAGE_TLS_MAX_BYTES || value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value)) invalid5();
949
+ if (bytes < 1 || bytes > MLS_DEV_KEY_PACKAGE_TLS_MAX_BYTES || value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value)) invalid6();
646
950
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
647
- if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid5();
951
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid6();
648
952
  return value;
649
953
  });
650
954
  }
651
955
  __name(parseMlsDevKeyPackageWire, "parseMlsDevKeyPackageWire");
652
956
  function parseMlsDevKeyPackageClaimPreconditions(value) {
653
- return boundary4(() => {
957
+ return boundary5(() => {
654
958
  const input = readMlsDataRecord(value, ["conversationId", "membershipRevision", "admissionId", "targetAdmissionId"]);
655
959
  return Object.freeze({
656
960
  conversationId: id2(input.conversationId),
@@ -662,17 +966,17 @@ function parseMlsDevKeyPackageClaimPreconditions(value) {
662
966
  }
663
967
  __name(parseMlsDevKeyPackageClaimPreconditions, "parseMlsDevKeyPackageClaimPreconditions");
664
968
  function parseMlsDevKeyPackagePublish(value) {
665
- return boundary4(() => {
969
+ return boundary5(() => {
666
970
  const input = readMlsDataRecord(value, ["version", "requestId", "keyPackage"]);
667
971
  return bounded4({ version: requireMlsLiteral(input.version, 1), requestId: requireMlsUuid(input.requestId), keyPackage: parseMlsDevKeyPackageWire(input.keyPackage) });
668
972
  });
669
973
  }
670
974
  __name(parseMlsDevKeyPackagePublish, "parseMlsDevKeyPackagePublish");
671
975
  function parseMlsDevKeyPackagePublicationReceipt(value) {
672
- return boundary4(() => {
976
+ return boundary5(() => {
673
977
  const input = readMlsDataRecord(value, ["version", "authorization", "requestId", "keyPackageRef", "deviceId", "publishedAtMs", "expiresAtMs"]);
674
978
  const publishedAtMs = requireMlsInteger(input.publishedAtMs), expiresAtMs = requireMlsInteger(input.expiresAtMs);
675
- if (publishedAtMs >= expiresAtMs) invalid5();
979
+ if (publishedAtMs >= expiresAtMs) invalid6();
676
980
  return bounded4({
677
981
  version: requireMlsLiteral(input.version, 1),
678
982
  authorization: requireMlsLiteral(input.authorization, "key_package_publication_only"),
@@ -686,7 +990,7 @@ function parseMlsDevKeyPackagePublicationReceipt(value) {
686
990
  }
687
991
  __name(parseMlsDevKeyPackagePublicationReceipt, "parseMlsDevKeyPackagePublicationReceipt");
688
992
  function parseMlsDevKeyPackageClaim(value) {
689
- return boundary4(() => {
993
+ return boundary5(() => {
690
994
  const input = readMlsDataRecord(value, ["version", "requestId", "claimantCredential", "recipientDeviceId", "preconditions"]);
691
995
  parseMlsDevCredentialToken(input.claimantCredential);
692
996
  return bounded4({
@@ -700,7 +1004,7 @@ function parseMlsDevKeyPackageClaim(value) {
700
1004
  }
701
1005
  __name(parseMlsDevKeyPackageClaim, "parseMlsDevKeyPackageClaim");
702
1006
  function parseMlsDevKeyPackageClaimReceipt(value) {
703
- return boundary4(() => {
1007
+ return boundary5(() => {
704
1008
  const input = readMlsDataRecord(value, [
705
1009
  "version",
706
1010
  "authorization",
@@ -713,7 +1017,7 @@ function parseMlsDevKeyPackageClaimReceipt(value) {
713
1017
  "claimedAtMs"
714
1018
  ]);
715
1019
  const claimantDeviceId = requireMlsUuid(input.claimantDeviceId), recipientDeviceId = requireMlsUuid(input.recipientDeviceId);
716
- if (claimantDeviceId === recipientDeviceId) invalid5();
1020
+ if (claimantDeviceId === recipientDeviceId) invalid6();
717
1021
  return bounded4({
718
1022
  version: requireMlsLiteral(input.version, 1),
719
1023
  authorization: requireMlsLiteral(input.authorization, "key_package_claim_only"),
@@ -729,6 +1033,228 @@ function parseMlsDevKeyPackageClaimReceipt(value) {
729
1033
  }
730
1034
  __name(parseMlsDevKeyPackageClaimReceipt, "parseMlsDevKeyPackageClaimReceipt");
731
1035
 
1036
+ // ../backend-contracts/src/mlsDevInteraction.ts
1037
+ var MLS_DEV_INTERACTION_LIMITS = Object.freeze({ title: 200, details: 8e3, options: 10, optionLabel: 120, text: 4e3 });
1038
+ var MLS_DEV_SECRET_ANSWER_MAX_BYTES = MLS_DEV_INTERACTION_LIMITS.text * 4 + 16;
1039
+ var MLS_DEV_INTERACTION_WITHDRAW_REASONS = ["stopped", "turn_ended", "expired", "restart"];
1040
+ var MlsDevInteractionValidationError = class extends Error {
1041
+ static {
1042
+ __name(this, "MlsDevInteractionValidationError");
1043
+ }
1044
+ code = "INVALID_MLS_DEV_INTERACTION";
1045
+ constructor() {
1046
+ super("INVALID_MLS_DEV_INTERACTION");
1047
+ this.name = "MlsDevInteractionValidationError";
1048
+ }
1049
+ };
1050
+ var utf83 = new TextEncoder();
1051
+ function invalid7() {
1052
+ throw new MlsDevInteractionValidationError();
1053
+ }
1054
+ __name(invalid7, "invalid");
1055
+ function boundary6(read) {
1056
+ try {
1057
+ return read();
1058
+ } catch {
1059
+ return invalid7();
1060
+ }
1061
+ }
1062
+ __name(boundary6, "boundary");
1063
+ function id3(value) {
1064
+ if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..") invalid7();
1065
+ return value;
1066
+ }
1067
+ __name(id3, "id");
1068
+ function interactionId(value) {
1069
+ if (typeof value !== "string" || !MLS_DEV_INTERACTION_ID_PATTERN.test(value) || value === "." || value === "..") invalid7();
1070
+ return value;
1071
+ }
1072
+ __name(interactionId, "interactionId");
1073
+ function encoded3(value, bytes) {
1074
+ decodeCanonicalMlsBase64Url(value, bytes);
1075
+ return value;
1076
+ }
1077
+ __name(encoded3, "encoded");
1078
+ function wire(value, min, max) {
1079
+ if (typeof value !== "string" || !/^[A-Za-z0-9_-]*$/.test(value) || value.length % 4 === 1) invalid7();
1080
+ const bytes = Math.floor(value.length * 3 / 4);
1081
+ if (bytes < min || bytes > max) invalid7();
1082
+ const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
1083
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid7();
1084
+ return value;
1085
+ }
1086
+ __name(wire, "wire");
1087
+ function text(value, max) {
1088
+ if (typeof value !== "string" || !value.trim() || [...value].length > max || new TextDecoder("utf-8", { fatal: true }).decode(utf83.encode(value)) !== value) invalid7();
1089
+ return value;
1090
+ }
1091
+ __name(text, "text");
1092
+ function boolean2(value) {
1093
+ if (typeof value !== "boolean") invalid7();
1094
+ return value;
1095
+ }
1096
+ __name(boolean2, "boolean");
1097
+ function array2(value, min, max) {
1098
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length < min || value.length > max) invalid7();
1099
+ const descriptors = Object.getOwnPropertyDescriptors(value);
1100
+ if (Reflect.ownKeys(descriptors).length !== value.length + 1) invalid7();
1101
+ return Array.from({ length: value.length }, (_, index) => {
1102
+ const field = descriptors[index];
1103
+ if (!field || !field.enumerable || !Object.hasOwn(field, "value")) invalid7();
1104
+ return field.value;
1105
+ });
1106
+ }
1107
+ __name(array2, "array");
1108
+ function closed(value, required, optional) {
1109
+ if (value === null || typeof value !== "object" || Array.isArray(value)) invalid7();
1110
+ const present2 = Reflect.ownKeys(value);
1111
+ if (present2.some((key) => typeof key !== "string" || !required.includes(key) && !optional.includes(key))) invalid7();
1112
+ return readMlsDataRecord(value, present2);
1113
+ }
1114
+ __name(closed, "closed");
1115
+ function ordered(value) {
1116
+ return Object.freeze(Object.fromEntries(Object.entries(value).filter(([, field]) => field !== void 0)));
1117
+ }
1118
+ __name(ordered, "ordered");
1119
+ function parseMlsDevInteractionRequestBody(value) {
1120
+ return boundary6(() => {
1121
+ const input = closed(
1122
+ value,
1123
+ ["requestId", "kind", "title", "responderIds", "expiresAtMs"],
1124
+ ["details", "options", "multiple", "risk", "allowSession", "scopeKey", "secretKey"]
1125
+ );
1126
+ const kind = input.kind;
1127
+ if (typeof kind !== "string" || !MLS_DEV_INTERACTION_KINDS.includes(kind)) invalid7();
1128
+ const has = /* @__PURE__ */ __name((key) => Object.hasOwn(input, key), "has");
1129
+ const options = has("options") ? array2(input.options, 1, MLS_DEV_INTERACTION_LIMITS.options).map((option) => {
1130
+ const fields2 = readMlsDataRecord(option, ["id", "label"]);
1131
+ if (typeof fields2.id !== "string" || !/^[A-Za-z0-9_.:-]{1,64}$/.test(fields2.id)) invalid7();
1132
+ return Object.freeze({ id: fields2.id, label: text(fields2.label, MLS_DEV_INTERACTION_LIMITS.optionLabel) });
1133
+ }) : void 0;
1134
+ if (options && new Set(options.map((option) => option.id)).size !== options.length) invalid7();
1135
+ const binding3 = parseMlsDevInteractionBinding({ role: "request", requestId: input.requestId, kind, responderIds: input.responderIds, expiresAtMs: input.expiresAtMs });
1136
+ if (binding3.role !== "request") invalid7();
1137
+ if (kind !== "approval" && ["risk", "allowSession", "scopeKey"].some(has)) invalid7();
1138
+ if (kind !== "question" && (has("options") || has("multiple"))) invalid7();
1139
+ if (has("multiple") && !options) invalid7();
1140
+ if (kind === "secret" !== has("secretKey")) invalid7();
1141
+ const allowSession = has("allowSession") ? boolean2(input.allowSession) : void 0;
1142
+ if (has("scopeKey") && (typeof input.scopeKey !== "string" || !/^[A-Za-z0-9_:-]{1,64}$/.test(input.scopeKey))) invalid7();
1143
+ if (allowSession === true && !has("scopeKey")) invalid7();
1144
+ if (has("risk") && input.risk !== "normal" && input.risk !== "destructive") invalid7();
1145
+ const secretKey = has("secretKey") ? (() => {
1146
+ const key = readMlsDataRecord(input.secretKey, ["kem", "publicKey"]);
1147
+ return Object.freeze({ kem: requireMlsLiteral(key.kem, "x25519"), publicKey: encoded3(key.publicKey, 32) });
1148
+ })() : void 0;
1149
+ return ordered({
1150
+ requestId: binding3.requestId,
1151
+ kind: binding3.kind,
1152
+ title: text(input.title, MLS_DEV_INTERACTION_LIMITS.title),
1153
+ details: has("details") ? text(input.details, MLS_DEV_INTERACTION_LIMITS.details) : void 0,
1154
+ options: options ? Object.freeze(options) : void 0,
1155
+ multiple: has("multiple") ? boolean2(input.multiple) : void 0,
1156
+ risk: input.risk,
1157
+ allowSession,
1158
+ scopeKey: input.scopeKey,
1159
+ responderIds: binding3.responderIds,
1160
+ expiresAtMs: binding3.expiresAtMs,
1161
+ secretKey
1162
+ });
1163
+ });
1164
+ }
1165
+ __name(parseMlsDevInteractionRequestBody, "parseMlsDevInteractionRequestBody");
1166
+ function parseMlsDevInteractionAnswer(value) {
1167
+ return boundary6(() => {
1168
+ if (value === null || typeof value !== "object" || Array.isArray(value)) invalid7();
1169
+ const keys2 = Reflect.ownKeys(value);
1170
+ if (keys2.includes("decision")) {
1171
+ const input = readMlsDataRecord(value, ["decision", "scope"]);
1172
+ if (input.decision !== "allow" && input.decision !== "deny" || input.scope !== "once" && input.scope !== "session") invalid7();
1173
+ return Object.freeze({ decision: input.decision, scope: input.scope });
1174
+ }
1175
+ if (keys2.includes("choices")) {
1176
+ const choices = array2(readMlsDataRecord(value, ["choices"]).choices, 1, MLS_DEV_INTERACTION_LIMITS.options).map((choice) => {
1177
+ if (typeof choice !== "string" || !/^[A-Za-z0-9_.:-]{1,64}$/.test(choice)) invalid7();
1178
+ return choice;
1179
+ });
1180
+ if (new Set(choices).size !== choices.length) invalid7();
1181
+ return Object.freeze({ choices: Object.freeze(choices) });
1182
+ }
1183
+ if (keys2.includes("text")) return Object.freeze({ text: text(readMlsDataRecord(value, ["text"]).text, MLS_DEV_INTERACTION_LIMITS.text) });
1184
+ if (keys2.includes("sealed")) {
1185
+ const sealed = readMlsDataRecord(readMlsDataRecord(value, ["sealed"]).sealed, ["enc", "ciphertext"]);
1186
+ return Object.freeze({ sealed: Object.freeze({ enc: encoded3(sealed.enc, 32), ciphertext: wire(sealed.ciphertext, 17, MLS_DEV_SECRET_ANSWER_MAX_BYTES) }) });
1187
+ }
1188
+ if (readMlsDataRecord(value, ["cancelled"]).cancelled !== true) invalid7();
1189
+ return Object.freeze({ cancelled: true });
1190
+ });
1191
+ }
1192
+ __name(parseMlsDevInteractionAnswer, "parseMlsDevInteractionAnswer");
1193
+ function parseMlsDevInteractionResponseBody(value) {
1194
+ return boundary6(() => {
1195
+ const input = readMlsDataRecord(value, ["requestId", "agentId", "answer"]);
1196
+ return Object.freeze({ requestId: interactionId(input.requestId), agentId: id3(input.agentId), answer: parseMlsDevInteractionAnswer(input.answer) });
1197
+ });
1198
+ }
1199
+ __name(parseMlsDevInteractionResponseBody, "parseMlsDevInteractionResponseBody");
1200
+ function parseMlsDevInteractionWithdrawBody(value) {
1201
+ return boundary6(() => {
1202
+ const input = readMlsDataRecord(value, ["requestId", "reason"]);
1203
+ if (!MLS_DEV_INTERACTION_WITHDRAW_REASONS.includes(input.reason)) invalid7();
1204
+ return Object.freeze({ requestId: interactionId(input.requestId), reason: input.reason });
1205
+ });
1206
+ }
1207
+ __name(parseMlsDevInteractionWithdrawBody, "parseMlsDevInteractionWithdrawBody");
1208
+ var payloadFields = ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId"];
1209
+ function parseMlsDevApplicationPayload(value) {
1210
+ return boundary6(() => {
1211
+ const kind = value && typeof value === "object" ? Object.getOwnPropertyDescriptor(value, "kind") : void 0;
1212
+ if (!kind || !Object.hasOwn(kind, "value")) invalid7();
1213
+ if (kind.value === "text") return parseMlsDevTextPayload(value);
1214
+ if (kind.value === "item") return parseMlsDevItemPayload(value);
1215
+ const input = readMlsDataRecord(value, [...payloadFields, "interaction"]);
1216
+ const ids = {
1217
+ version: requireMlsLiteral(input.version, 1),
1218
+ kind: input.kind,
1219
+ conversationId: id3(input.conversationId),
1220
+ groupId: encoded3(input.groupId, 32),
1221
+ messageId: id3(input.messageId),
1222
+ operationId: id3(input.operationId),
1223
+ senderDeviceId: requireMlsUuid(input.senderDeviceId)
1224
+ };
1225
+ if (ids.messageId.startsWith("membership-")) invalid7();
1226
+ const interaction = kind.value === "interaction.request" ? parseMlsDevInteractionRequestBody(input.interaction) : kind.value === "interaction.response" ? parseMlsDevInteractionResponseBody(input.interaction) : kind.value === "interaction.withdraw" ? parseMlsDevInteractionWithdrawBody(input.interaction) : invalid7();
1227
+ const payload = Object.freeze({ ...ids, interaction });
1228
+ if (utf83.encode(JSON.stringify(payload)).length > MLS_DEV_TEXT_MAX_BYTES) invalid7();
1229
+ return payload;
1230
+ });
1231
+ }
1232
+ __name(parseMlsDevApplicationPayload, "parseMlsDevApplicationPayload");
1233
+ function assertMlsDevInteractionPayloadBinding(payload, binding3) {
1234
+ boundary6(() => {
1235
+ if (payload.kind === "text" || payload.kind === "item") {
1236
+ if (binding3 !== void 0) invalid7();
1237
+ return;
1238
+ }
1239
+ if (!binding3 || payload.interaction.requestId !== binding3.requestId) invalid7();
1240
+ if (payload.kind === "interaction.request") {
1241
+ if (binding3.role !== "request" || payload.interaction.kind !== binding3.kind || payload.interaction.expiresAtMs !== binding3.expiresAtMs || payload.interaction.responderIds.length !== 1 || payload.interaction.responderIds[0] !== binding3.responderIds[0]) invalid7();
1242
+ } else if (payload.kind === "interaction.response") {
1243
+ if (binding3.role !== "response" || payload.interaction.agentId !== binding3.agentId) invalid7();
1244
+ } else if (binding3.role !== "withdraw") invalid7();
1245
+ });
1246
+ }
1247
+ __name(assertMlsDevInteractionPayloadBinding, "assertMlsDevInteractionPayloadBinding");
1248
+ function isMlsDevInteractionAnswerAllowed(request, answer) {
1249
+ if ("cancelled" in answer) return request.kind !== "approval";
1250
+ if (request.kind === "approval") return "decision" in answer && (answer.scope !== "session" || request.allowSession === true);
1251
+ if (request.kind === "secret") return "sealed" in answer;
1252
+ if ("text" in answer) return !request.options;
1253
+ if (!("choices" in answer) || !request.options) return false;
1254
+ return (request.multiple === true || answer.choices.length === 1) && answer.choices.every((choice) => request.options.some((option) => option.id === choice));
1255
+ }
1256
+ __name(isMlsDevInteractionAnswerAllowed, "isMlsDevInteractionAnswerAllowed");
1257
+
732
1258
  // ../backend-contracts/src/mlsDevGroup.ts
733
1259
  var MLS_DEV_GROUP_ROSTER_MAX = 32;
734
1260
  var MLS_DEV_GROUP_TLS_MAX_BYTES = 256 * 1024;
@@ -737,6 +1263,7 @@ var MLS_DEV_GROUP_WRAPPED_MAX_BYTES = 3 * 1024 * 1024;
737
1263
  var MLS_DEV_GROUP_PREPARATION_MAX_BYTES = 4 * 1024 * 1024;
738
1264
  var MLS_DEV_GROUP_QUERY_MAX_BYTES = 4 * 1024 * 1024;
739
1265
  var MLS_DEV_GROUP_QUERY_MAX_CONTROLS = 4;
1266
+ var MLS_DEV_GROUP_ADMISSION_MAX_CANDIDATES = 64;
740
1267
  var MlsDevGroupValidationError = class extends Error {
741
1268
  static {
742
1269
  __name(this, "MlsDevGroupValidationError");
@@ -747,119 +1274,169 @@ var MlsDevGroupValidationError = class extends Error {
747
1274
  this.name = "MlsDevGroupValidationError";
748
1275
  }
749
1276
  };
750
- var utf83 = new TextEncoder();
751
- function invalid6() {
1277
+ var utf84 = new TextEncoder();
1278
+ function invalid8() {
752
1279
  throw new MlsDevGroupValidationError();
753
1280
  }
754
- __name(invalid6, "invalid");
755
- function boundary5(read) {
1281
+ __name(invalid8, "invalid");
1282
+ function boundary7(read) {
756
1283
  try {
757
1284
  return read();
758
1285
  } catch {
759
- return invalid6();
1286
+ return invalid8();
760
1287
  }
761
1288
  }
762
- __name(boundary5, "boundary");
1289
+ __name(boundary7, "boundary");
763
1290
  function bounded5(value, maximum = MLS_DEV_GROUP_CONTROL_MAX_BYTES) {
764
- if (utf83.encode(JSON.stringify(value)).length > maximum)
765
- invalid6();
1291
+ if (utf84.encode(JSON.stringify(value)).length > maximum)
1292
+ invalid8();
766
1293
  return Object.freeze(value);
767
1294
  }
768
1295
  __name(bounded5, "bounded");
769
- function id3(value) {
1296
+ function id4(value) {
770
1297
  if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..")
771
- invalid6();
1298
+ invalid8();
772
1299
  return value;
773
1300
  }
774
- __name(id3, "id");
775
- function encoded3(value, bytes) {
1301
+ __name(id4, "id");
1302
+ function encoded4(value, bytes) {
776
1303
  decodeCanonicalMlsBase64Url(value, bytes);
777
1304
  return value;
778
1305
  }
779
- __name(encoded3, "encoded");
780
- function boolean2(value) {
1306
+ __name(encoded4, "encoded");
1307
+ function boolean3(value) {
781
1308
  if (typeof value !== "boolean")
782
- invalid6();
1309
+ invalid8();
783
1310
  return value;
784
1311
  }
785
- __name(boolean2, "boolean");
1312
+ __name(boolean3, "boolean");
1313
+ function textProtocol(value) {
1314
+ if (!isMlsDevTextProtocol(value))
1315
+ invalid8();
1316
+ return value;
1317
+ }
1318
+ __name(textProtocol, "textProtocol");
786
1319
  function token(value) {
787
1320
  parseMlsDevCredentialToken(value);
788
1321
  return value;
789
1322
  }
790
1323
  __name(token, "token");
791
- function wire(value) {
1324
+ function wire2(value) {
792
1325
  if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_GROUP_TLS_MAX_BYTES * 4 / 3))
793
- invalid6();
1326
+ invalid8();
794
1327
  const bytes = Math.floor(value.length * 3 / 4);
795
1328
  if (value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value))
796
- invalid6();
1329
+ invalid8();
797
1330
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
798
1331
  if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0)
799
- invalid6();
1332
+ invalid8();
800
1333
  return value;
801
1334
  }
802
- __name(wire, "wire");
803
- function array2(value, maximum) {
1335
+ __name(wire2, "wire");
1336
+ function plaintextJson(value) {
1337
+ if (typeof value !== "string" || !value || utf84.encode(value).length > MLS_DEV_TEXT_MAX_BYTES || new TextDecoder("utf-8", { fatal: true }).decode(utf84.encode(value)) !== value)
1338
+ invalid8();
1339
+ return value;
1340
+ }
1341
+ __name(plaintextJson, "plaintextJson");
1342
+ function present(value, keys2) {
1343
+ return value && typeof value === "object" ? keys2.filter((key) => Object.hasOwn(value, key)) : [];
1344
+ }
1345
+ __name(present, "present");
1346
+ var pick = /* @__PURE__ */ __name((value, keys2) => Object.fromEntries(keys2.map((key) => [key, value[key]])), "pick");
1347
+ var textExtras = /* @__PURE__ */ __name((text5) => ({ ...text5.replyTo ? { replyTo: text5.replyTo } : {}, ...text5.mentions ? { mentions: text5.mentions } : {} }), "textExtras");
1348
+ function sealedCiphertext(value) {
1349
+ if (typeof value !== "string" || !/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1) invalid8();
1350
+ const bytes = Math.floor(value.length * 3 / 4);
1351
+ if (bytes < 17 || bytes > MLS_DEV_SECRET_ANSWER_MAX_BYTES) invalid8();
1352
+ const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
1353
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid8();
1354
+ return value;
1355
+ }
1356
+ __name(sealedCiphertext, "sealedCiphertext");
1357
+ function array3(value, maximum) {
804
1358
  if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > maximum)
805
- invalid6();
1359
+ invalid8();
806
1360
  const descriptors = Object.getOwnPropertyDescriptors(value);
807
1361
  if (Reflect.ownKeys(descriptors).length !== value.length + 1)
808
- invalid6();
1362
+ invalid8();
809
1363
  return Array.from({ length: value.length }, (_, index) => {
810
1364
  const descriptor = descriptors[index];
811
1365
  if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, "value"))
812
- invalid6();
1366
+ invalid8();
813
1367
  return descriptor.value;
814
1368
  });
815
1369
  }
816
- __name(array2, "array");
1370
+ __name(array3, "array");
817
1371
  function parseMlsDevGroupCreateConversation(value) {
818
- return boundary5(() => {
1372
+ return boundary7(() => {
819
1373
  const input = readMlsDataRecord(value, ["name", "memberIds", "mlsDev"]), config = readMlsDataRecord(input.mlsDev, ["version", "conversationId", "credential"], ["version", "conversationId", "credential", "protocol"]);
820
1374
  if (typeof input.name !== "string" || input.name.trim().length > 100)
821
- invalid6();
822
- const memberIds = array2(input.memberIds, 31).map((value2) => parseMlsDevEnrollmentPrincipal({ type: "human", id: value2 }).id);
1375
+ invalid8();
1376
+ const memberIds = array3(input.memberIds, 31).map((value2) => parseMlsDevEnrollmentPrincipal({ type: "human", id: value2 }).id);
823
1377
  if (!memberIds.length || new Set(memberIds).size !== memberIds.length || memberIds.some((value2) => value2.includes("/") || value2 === "." || value2 === ".."))
824
- invalid6();
825
- return bounded5({ name: input.name, memberIds: Object.freeze(memberIds), mlsDev: Object.freeze({ version: requireMlsLiteral(config.version, 1), conversationId: id3(config.conversationId), credential: token(config.credential), ...Object.hasOwn(config, "protocol") ? { protocol: requireMlsLiteral(config.protocol, MLS_DEV_TEXT_PROTOCOL) } : {} }) }, 16 * 1024);
1378
+ invalid8();
1379
+ return bounded5({ name: input.name, memberIds: Object.freeze(memberIds), mlsDev: Object.freeze({ version: requireMlsLiteral(config.version, 1), conversationId: id4(config.conversationId), credential: token(config.credential), ...Object.hasOwn(config, "protocol") ? { protocol: textProtocol(config.protocol) } : {} }) }, 16 * 1024);
826
1380
  });
827
1381
  }
828
1382
  __name(parseMlsDevGroupCreateConversation, "parseMlsDevGroupCreateConversation");
829
1383
  function parseMlsDevGroupHead(value) {
830
- return boundary5(() => {
1384
+ return boundary7(() => {
831
1385
  const input = readMlsDataRecord(value, ["sequence", "epoch", "hash"]);
832
- return Object.freeze({ sequence: requireMlsInteger(input.sequence, 1), epoch: requireMlsInteger(input.epoch), hash: encoded3(input.hash, 32) });
1386
+ return Object.freeze({ sequence: requireMlsInteger(input.sequence, 1), epoch: requireMlsInteger(input.epoch), hash: encoded4(input.hash, 32) });
833
1387
  });
834
1388
  }
835
1389
  __name(parseMlsDevGroupHead, "parseMlsDevGroupHead");
836
1390
  function parseMlsDevGroupMarker(value) {
837
- return boundary5(() => {
1391
+ return boundary7(() => {
838
1392
  const input = readMlsDataRecord(value, ["version", "groupId", "head"]);
839
- return Object.freeze({ version: requireMlsLiteral(input.version, 1), groupId: encoded3(input.groupId, 32), head: parseMlsDevGroupHead(input.head) });
1393
+ return Object.freeze({ version: requireMlsLiteral(input.version, 1), groupId: encoded4(input.groupId, 32), head: parseMlsDevGroupHead(input.head) });
840
1394
  });
841
1395
  }
842
1396
  __name(parseMlsDevGroupMarker, "parseMlsDevGroupMarker");
843
1397
  function parseMlsDevGroupRoster(value) {
844
- return boundary5(() => {
845
- const values = array2(value, MLS_DEV_GROUP_ROSTER_MAX).map((item) => {
846
- const entry = readMlsDataRecord(item, ["device", "admissionId"]);
847
- return Object.freeze({ device: parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: entry.device }).device, admissionId: id3(entry.admissionId) });
1398
+ return boundary7(() => {
1399
+ const values = array3(value, MLS_DEV_GROUP_ROSTER_MAX).map((item2) => {
1400
+ const entry = readMlsDataRecord(item2, ["device", "admissionId"]);
1401
+ return Object.freeze({ device: parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: entry.device }).device, admissionId: id4(entry.admissionId) });
848
1402
  });
849
1403
  for (let i = 1; i < values.length; i++)
850
1404
  if (values[i - 1].device.deviceId >= values[i].device.deviceId)
851
- invalid6();
1405
+ invalid8();
852
1406
  return Object.freeze(values);
853
1407
  });
854
1408
  }
855
1409
  __name(parseMlsDevGroupRoster, "parseMlsDevGroupRoster");
1410
+ var MLS_DEV_ROOM_REMOVAL_DEADLINE_MS = 72 * 60 * 60 * 1e3;
1411
+ function parseMlsDevRoomRemoval(value) {
1412
+ return boundary7(() => {
1413
+ const input = readMlsDataRecord(value, ["version", "status", "pending", "closedAtMs"]), devices = /* @__PURE__ */ new Set(), principals = /* @__PURE__ */ new Set();
1414
+ const status = ["pending", "closing", "closed"].includes(input.status) ? input.status : invalid8();
1415
+ const pending = array3(input.pending, MLS_DEV_GROUP_ROSTER_MAX).map((item2) => {
1416
+ const entry = readMlsDataRecord(item2, ["principalId", "deviceIds", "deadlineAtMs"]);
1417
+ const principalId2 = parseMlsDevEnrollmentPrincipal({ type: "human", id: entry.principalId }).id;
1418
+ const deviceIds = array3(entry.deviceIds, MLS_DEV_GROUP_ROSTER_MAX).map(requireMlsUuid);
1419
+ if (principals.has(principalId2)) invalid8();
1420
+ principals.add(principalId2);
1421
+ for (const deviceId of deviceIds) {
1422
+ if (devices.has(deviceId)) invalid8();
1423
+ devices.add(deviceId);
1424
+ }
1425
+ return Object.freeze({ principalId: principalId2, deviceIds: Object.freeze(deviceIds), deadlineAtMs: requireMlsInteger(entry.deadlineAtMs, 1) });
1426
+ });
1427
+ const closedAtMs = input.closedAtMs === null ? null : requireMlsInteger(input.closedAtMs, 1);
1428
+ if (status === "pending" ? !pending.length || closedAtMs !== null : closedAtMs === null || status === "closed" && pending.length) invalid8();
1429
+ return Object.freeze({ version: requireMlsLiteral(input.version, 1), status, pending: Object.freeze(pending), closedAtMs });
1430
+ });
1431
+ }
1432
+ __name(parseMlsDevRoomRemoval, "parseMlsDevRoomRemoval");
856
1433
  function parseMlsDevGroupPreconditions(value) {
857
- return boundary5(() => {
1434
+ return boundary7(() => {
858
1435
  const input = readMlsDataRecord(value, ["membershipRevision", "admissionId", "targetAdmissionId"]);
859
1436
  return Object.freeze({
860
1437
  membershipRevision: requireMlsInteger(input.membershipRevision),
861
- admissionId: id3(input.admissionId),
862
- targetAdmissionId: input.targetAdmissionId === null ? null : id3(input.targetAdmissionId)
1438
+ admissionId: id4(input.admissionId),
1439
+ targetAdmissionId: input.targetAdmissionId === null ? null : id4(input.targetAdmissionId)
863
1440
  });
864
1441
  });
865
1442
  }
@@ -883,37 +1460,40 @@ var unsignedFields = [
883
1460
  ];
884
1461
  function unsigned(input) {
885
1462
  if (typeof input.kind !== "string" || !["create", "add", "remove"].includes(input.kind))
886
- invalid6();
1463
+ invalid8();
887
1464
  const kind = input.kind;
888
1465
  const senderCredential = token(input.senderCredential), sender = parseMlsDevCredentialToken(senderCredential).unsigned.claims.device;
889
1466
  const expectedHead = input.expectedHead === null ? null : parseMlsDevGroupHead(input.expectedHead);
890
1467
  const epoch = requireMlsInteger(input.epoch), preconditions = parseMlsDevGroupPreconditions(input.preconditions), roster = parseMlsDevGroupRoster(input.roster);
891
- const groupInfo = input.groupInfo === null ? null : wire(input.groupInfo), commit = input.commit === null ? null : wire(input.commit);
892
- const welcome = input.welcome === null ? null : wire(input.welcome);
1468
+ const environmentId = requireMlsEnvironmentId(input.environmentId);
1469
+ if (sender.environmentId !== environmentId || roster.some((entry) => entry.device.environmentId !== environmentId))
1470
+ invalid8();
1471
+ const groupInfo = input.groupInfo === null ? null : wire2(input.groupInfo), commit = input.commit === null ? null : wire2(input.commit);
1472
+ const welcome = input.welcome === null ? null : wire2(input.welcome);
893
1473
  const keyPackageClaim = input.keyPackageClaim === null ? null : parseMlsDevKeyPackageClaimReceipt(input.keyPackageClaim);
894
1474
  const removedDeviceId = input.removedDeviceId === null ? null : requireMlsUuid(input.removedDeviceId);
895
1475
  const own = roster.find((entry) => entry.device.deviceId === sender.deviceId);
896
1476
  if (!own || JSON.stringify(own.device) !== JSON.stringify(sender) || own.admissionId !== preconditions.admissionId)
897
- invalid6();
1477
+ invalid8();
898
1478
  if (kind === "create") {
899
1479
  if (expectedHead !== null || epoch !== 0 || roster.length !== 1 || !groupInfo || commit !== null || welcome !== null || keyPackageClaim !== null || removedDeviceId !== null || preconditions.targetAdmissionId !== null)
900
- invalid6();
1480
+ invalid8();
901
1481
  } else {
902
1482
  if (!expectedHead || expectedHead.sequence >= Number.MAX_SAFE_INTEGER || expectedHead.epoch >= Number.MAX_SAFE_INTEGER || epoch !== expectedHead.epoch + 1 || !commit || preconditions.targetAdmissionId === null)
903
- invalid6();
1483
+ invalid8();
904
1484
  if (kind === "add") {
905
1485
  const target = roster.find((entry) => entry.device.deviceId === keyPackageClaim?.recipientDeviceId);
906
1486
  if (!welcome || !keyPackageClaim || removedDeviceId !== null || !target || keyPackageClaim.claimantDeviceId !== sender.deviceId || keyPackageClaim.preconditions.conversationId !== input.conversationId || keyPackageClaim.preconditions.membershipRevision !== preconditions.membershipRevision || keyPackageClaim.preconditions.admissionId !== preconditions.admissionId || keyPackageClaim.preconditions.targetAdmissionId !== preconditions.targetAdmissionId || target.admissionId !== preconditions.targetAdmissionId)
907
- invalid6();
1487
+ invalid8();
908
1488
  } else if (!removedDeviceId || removedDeviceId === sender.deviceId || roster.some((entry) => entry.device.deviceId === removedDeviceId) || welcome !== null || keyPackageClaim !== null)
909
- invalid6();
1489
+ invalid8();
910
1490
  }
911
1491
  return bounded5({
912
1492
  version: requireMlsLiteral(input.version, 1),
913
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
1493
+ environmentId,
914
1494
  kind,
915
- conversationId: id3(input.conversationId),
916
- groupId: encoded3(input.groupId, 32),
1495
+ conversationId: id4(input.conversationId),
1496
+ groupId: encoded4(input.groupId, 32),
917
1497
  senderCredential,
918
1498
  expectedHead,
919
1499
  epoch,
@@ -928,25 +1508,25 @@ function unsigned(input) {
928
1508
  }
929
1509
  __name(unsigned, "unsigned");
930
1510
  function parseMlsDevGroupControl(value) {
931
- return boundary5(() => {
1511
+ return boundary7(() => {
932
1512
  const input = readMlsDataRecord(value, [...unsignedFields, "proof"]);
933
- return bounded5({ ...unsigned(input), proof: encoded3(input.proof, 64) });
1513
+ return bounded5({ ...unsigned(input), proof: encoded4(input.proof, 64) });
934
1514
  });
935
1515
  }
936
1516
  __name(parseMlsDevGroupControl, "parseMlsDevGroupControl");
937
1517
  function parseMlsDevGroupAcceptedControl(value) {
938
- return boundary5(() => {
1518
+ return boundary7(() => {
939
1519
  const input = readMlsDataRecord(value, ["version", "authorization", "operationId", "control", "head", "acceptedAtMs", "membershipRevision"]);
940
1520
  const control = parseMlsDevGroupControl(input.control), head = parseMlsDevGroupHead(input.head);
941
1521
  if (head.sequence !== (control.expectedHead?.sequence ?? 0) + 1 || head.epoch !== control.epoch)
942
- invalid6();
1522
+ invalid8();
943
1523
  const membershipRevision = requireMlsInteger(input.membershipRevision);
944
1524
  if (membershipRevision !== control.preconditions.membershipRevision && !(control.kind === "remove" && membershipRevision === control.preconditions.membershipRevision + 1))
945
- invalid6();
1525
+ invalid8();
946
1526
  return bounded5({
947
1527
  version: requireMlsLiteral(input.version, 1),
948
1528
  authorization: requireMlsLiteral(input.authorization, "group_control_only"),
949
- operationId: id3(input.operationId),
1529
+ operationId: id4(input.operationId),
950
1530
  control,
951
1531
  head,
952
1532
  acceptedAtMs: requireMlsInteger(input.acceptedAtMs),
@@ -955,40 +1535,65 @@ function parseMlsDevGroupAcceptedControl(value) {
955
1535
  });
956
1536
  }
957
1537
  __name(parseMlsDevGroupAcceptedControl, "parseMlsDevGroupAcceptedControl");
1538
+ function parseMlsDevGroupAdmissionsResult(value) {
1539
+ return boundary7(() => {
1540
+ const input = readMlsDataRecord(value, ["version", "conversationId", "membershipRevision", "candidates", "waitingPrincipalIds"]);
1541
+ const candidates = array3(input.candidates, MLS_DEV_GROUP_ADMISSION_MAX_CANDIDATES).map((raw) => {
1542
+ const entry = readMlsDataRecord(raw, ["principal", "deviceId", "targetAdmissionId"]), principal2 = readMlsDataRecord(entry.principal, ["type", "id"]);
1543
+ if (principal2.type !== "human" && principal2.type !== "ai_agent") invalid8();
1544
+ return Object.freeze({
1545
+ principal: Object.freeze({ type: principal2.type, id: id4(principal2.id) }),
1546
+ deviceId: requireMlsUuid(entry.deviceId),
1547
+ targetAdmissionId: id4(entry.targetAdmissionId)
1548
+ });
1549
+ });
1550
+ if (new Set(candidates.map((entry) => entry.deviceId)).size !== candidates.length) invalid8();
1551
+ const waiting = array3(input.waitingPrincipalIds, 32).map(id4);
1552
+ if (new Set(waiting).size !== waiting.length) invalid8();
1553
+ return bounded5(Object.freeze({
1554
+ version: requireMlsLiteral(input.version, 1),
1555
+ conversationId: id4(input.conversationId),
1556
+ membershipRevision: requireMlsInteger(input.membershipRevision, 1),
1557
+ candidates: Object.freeze(candidates),
1558
+ waitingPrincipalIds: Object.freeze(waiting)
1559
+ }), 64 * 1024);
1560
+ });
1561
+ }
1562
+ __name(parseMlsDevGroupAdmissionsResult, "parseMlsDevGroupAdmissionsResult");
958
1563
  function parseMlsDevGroupQuery(value) {
959
- return boundary5(() => {
1564
+ return boundary7(() => {
960
1565
  const input = readMlsDataRecord(value, ["version", "conversationId", "credential", "afterSequence", "limit"]);
961
- const limit = requireMlsInteger(input.limit, 1);
962
- if (limit > MLS_DEV_GROUP_QUERY_MAX_CONTROLS)
963
- invalid6();
1566
+ const limit2 = requireMlsInteger(input.limit, 1);
1567
+ if (limit2 > MLS_DEV_GROUP_QUERY_MAX_CONTROLS)
1568
+ invalid8();
964
1569
  return bounded5({
965
1570
  version: requireMlsLiteral(input.version, 1),
966
- conversationId: id3(input.conversationId),
1571
+ conversationId: id4(input.conversationId),
967
1572
  credential: token(input.credential),
968
1573
  afterSequence: requireMlsInteger(input.afterSequence),
969
- limit
1574
+ limit: limit2
970
1575
  }, 16 * 1024);
971
1576
  });
972
1577
  }
973
1578
  __name(parseMlsDevGroupQuery, "parseMlsDevGroupQuery");
974
1579
  function parseMlsDevGroupQueryResult(value) {
975
- return boundary5(() => {
1580
+ return boundary7(() => {
976
1581
  const input = readMlsDataRecord(value, ["version", "conversationId", "marker", "membershipRevision", "admissionId", "roster", "controls", "nextSequence", "hasMore", "terminal"]);
977
- const conversationId = id3(input.conversationId), marker = input.marker === null ? null : parseMlsDevGroupMarker(input.marker);
978
- const controls = array2(input.controls, MLS_DEV_GROUP_QUERY_MAX_CONTROLS).map(parseMlsDevGroupAcceptedControl);
979
- const nextSequence = requireMlsInteger(input.nextSequence), terminal = boolean2(input.terminal), hasMore = boolean2(input.hasMore);
1582
+ const conversationId = id4(input.conversationId), marker = input.marker === null ? null : parseMlsDevGroupMarker(input.marker);
1583
+ const controls = array3(input.controls, MLS_DEV_GROUP_QUERY_MAX_CONTROLS).map(parseMlsDevGroupAcceptedControl);
1584
+ const nextSequence = requireMlsInteger(input.nextSequence), terminal = boolean3(input.terminal), hasMore = boolean3(input.hasMore);
980
1585
  for (let i = 0; i < controls.length; i++) {
981
1586
  if (!marker || controls[i].control.conversationId !== conversationId || controls[i].control.groupId !== marker.groupId || controls[i].head.sequence > marker.head.sequence || i > 0 && controls[i].head.sequence !== controls[i - 1].head.sequence + 1)
982
- invalid6();
1587
+ invalid8();
983
1588
  }
984
1589
  if (controls.length && controls.at(-1).head.sequence !== nextSequence || marker && nextSequence > marker.head.sequence || !marker && (controls.length || nextSequence || terminal || hasMore))
985
- invalid6();
1590
+ invalid8();
986
1591
  return bounded5({
987
1592
  version: requireMlsLiteral(input.version, 1),
988
1593
  conversationId,
989
1594
  marker,
990
1595
  membershipRevision: requireMlsInteger(input.membershipRevision),
991
- admissionId: id3(input.admissionId),
1596
+ admissionId: id4(input.admissionId),
992
1597
  roster: parseMlsDevGroupRoster(input.roster),
993
1598
  controls: Object.freeze(controls),
994
1599
  nextSequence,
@@ -999,42 +1604,43 @@ function parseMlsDevGroupQueryResult(value) {
999
1604
  }
1000
1605
  __name(parseMlsDevGroupQueryResult, "parseMlsDevGroupQueryResult");
1001
1606
  function parseMlsDevGroupContext(value) {
1002
- return boundary5(() => {
1607
+ return boundary7(() => {
1003
1608
  const input = readMlsDataRecord(value, ["version", "environmentId", "conversationId", "groupId", "deviceId", "installationId", "revision"], ["version", "environmentId", "conversationId", "groupId", "deviceId", "installationId", "revision", "protocol"]);
1004
1609
  const revision2 = requireMlsInteger(input.revision);
1005
1610
  if (revision2 >= Number.MAX_SAFE_INTEGER)
1006
- invalid6();
1611
+ invalid8();
1007
1612
  return Object.freeze({
1008
1613
  version: requireMlsLiteral(input.version, 1),
1009
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
1010
- conversationId: id3(input.conversationId),
1011
- groupId: encoded3(input.groupId, 32),
1614
+ environmentId: requireMlsEnvironmentId(input.environmentId),
1615
+ conversationId: id4(input.conversationId),
1616
+ groupId: encoded4(input.groupId, 32),
1012
1617
  deviceId: requireMlsUuid(input.deviceId),
1013
1618
  installationId: parseMlsDevInstallationId(input.installationId),
1014
1619
  revision: revision2,
1015
- ...Object.hasOwn(input, "protocol") ? { protocol: requireMlsLiteral(input.protocol, MLS_DEV_TEXT_PROTOCOL) } : {}
1620
+ ...Object.hasOwn(input, "protocol") ? { protocol: textProtocol(input.protocol) } : {}
1016
1621
  });
1017
1622
  });
1018
1623
  }
1019
1624
  __name(parseMlsDevGroupContext, "parseMlsDevGroupContext");
1020
1625
  function parseMlsDevGroupCommand(value) {
1021
- return boundary5(() => {
1626
+ return boundary7(() => {
1022
1627
  if (!value || typeof value !== "object")
1023
- invalid6();
1628
+ invalid8();
1024
1629
  const descriptor = Object.getOwnPropertyDescriptor(value, "op");
1025
1630
  if (!descriptor || !Object.hasOwn(descriptor, "value"))
1026
- invalid6();
1631
+ invalid8();
1027
1632
  const op = descriptor.value;
1028
1633
  if (op === "process_application") {
1029
1634
  const input2 = readMlsDataRecord(value, ["op", "entry"]), entry = parseMlsDevGroupFeedEntry(input2.entry);
1030
- if (entry.kind !== "application")
1031
- invalid6();
1635
+ if (entry.kind !== "application" || !entry.receiptProof)
1636
+ invalid8();
1032
1637
  return bounded5({ op, entry });
1033
1638
  }
1034
1639
  if (op === "encrypt_text") {
1035
- const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "text"]);
1640
+ const extras = present(value, ["replyTo", "mentions"]);
1641
+ const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "text", ...extras]);
1036
1642
  const credential = token(input2.credential), senderDeviceId = parseMlsDevCredentialToken(credential).unsigned.claims.device.deviceId;
1037
- const text3 = parseMlsDevTextPayload({
1643
+ const text5 = parseMlsDevTextPayload({
1038
1644
  version: 1,
1039
1645
  kind: "text",
1040
1646
  conversationId: "validation",
@@ -1042,117 +1648,283 @@ function parseMlsDevGroupCommand(value) {
1042
1648
  messageId: input2.messageId,
1043
1649
  operationId: input2.operationId,
1044
1650
  senderDeviceId,
1045
- text: input2.text
1651
+ text: input2.text,
1652
+ ...pick(input2, extras)
1046
1653
  });
1047
1654
  return bounded5({
1048
1655
  op,
1049
- operationId: text3.operationId,
1050
- messageId: text3.messageId,
1656
+ operationId: text5.operationId,
1657
+ messageId: text5.messageId,
1051
1658
  credential,
1052
1659
  expectedHead: parseMlsDevGroupHead(input2.expectedHead),
1053
1660
  preconditions: parseMlsDevApplicationPreconditions(input2.preconditions),
1054
- text: text3.text
1661
+ text: text5.text,
1662
+ ...textExtras(text5)
1663
+ });
1664
+ }
1665
+ if (op === "encrypt_item") {
1666
+ const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "item"]);
1667
+ const credential = token(input2.credential), senderDeviceId = parseMlsDevCredentialToken(credential).unsigned.claims.device.deviceId;
1668
+ const parsed = parseMlsDevItemPayload({
1669
+ version: 1,
1670
+ kind: "item",
1671
+ conversationId: "validation",
1672
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1673
+ messageId: input2.messageId,
1674
+ operationId: input2.operationId,
1675
+ senderDeviceId,
1676
+ item: input2.item
1677
+ });
1678
+ return bounded5({
1679
+ op,
1680
+ operationId: parsed.operationId,
1681
+ messageId: parsed.messageId,
1682
+ credential,
1683
+ expectedHead: parseMlsDevGroupHead(input2.expectedHead),
1684
+ preconditions: parseMlsDevApplicationPreconditions(input2.preconditions),
1685
+ item: parsed.item
1686
+ });
1687
+ }
1688
+ if (op === "encrypt_interaction") {
1689
+ const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "interaction", "body", "seal"]);
1690
+ const credential = token(input2.credential), interaction = parseMlsDevInteractionBinding(input2.interaction);
1691
+ const body = readMlsDataRecord(input2.body, Reflect.ownKeys(input2.body ?? {}).filter((key) => typeof key === "string"));
1692
+ let seal = null;
1693
+ if (interaction.role === "request") {
1694
+ if (Object.hasOwn(body, "secretKey") || input2.seal !== null)
1695
+ invalid8();
1696
+ const parsed = parseMlsDevInteractionRequestBody(interaction.kind === "secret" ? { ...body, secretKey: { kem: "x25519", publicKey: "A".repeat(43) } } : body);
1697
+ if (parsed.requestId !== interaction.requestId || parsed.kind !== interaction.kind || parsed.expiresAtMs !== interaction.expiresAtMs || parsed.responderIds[0] !== interaction.responderIds[0])
1698
+ invalid8();
1699
+ } else if (interaction.role === "response") {
1700
+ if (input2.seal === null) {
1701
+ const parsed = parseMlsDevInteractionResponseBody(body);
1702
+ if (parsed.requestId !== interaction.requestId || parsed.agentId !== interaction.agentId || "sealed" in parsed.answer)
1703
+ invalid8();
1704
+ } else {
1705
+ const fields3 = readMlsDataRecord(input2.seal, ["text", "publicKey", "requesterDeviceId"]), ids2 = readMlsDataRecord(body, ["requestId", "agentId"]);
1706
+ if (ids2.requestId !== interaction.requestId || ids2.agentId !== interaction.agentId || typeof fields3.text !== "string" || !fields3.text.trim() || [...fields3.text].length > MLS_DEV_INTERACTION_LIMITS.text || utf84.encode(fields3.text).length > MLS_DEV_SECRET_ANSWER_MAX_BYTES - 16 || new TextDecoder("utf-8", { fatal: true }).decode(utf84.encode(fields3.text)) !== fields3.text)
1707
+ invalid8();
1708
+ seal = Object.freeze({ text: fields3.text, publicKey: encoded4(fields3.publicKey, 32), requesterDeviceId: requireMlsUuid(fields3.requesterDeviceId) });
1709
+ }
1710
+ } else if (input2.seal !== null || parseMlsDevInteractionWithdrawBody(body).requestId !== interaction.requestId)
1711
+ invalid8();
1712
+ const ids = parseMlsDevTextPayload({
1713
+ version: 1,
1714
+ kind: "text",
1715
+ conversationId: "validation",
1716
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1717
+ messageId: input2.messageId,
1718
+ operationId: input2.operationId,
1719
+ senderDeviceId: parseMlsDevCredentialToken(credential).unsigned.claims.device.deviceId,
1720
+ text: "x"
1721
+ });
1722
+ if (utf84.encode(JSON.stringify(body)).length > MLS_DEV_TEXT_MAX_BYTES)
1723
+ invalid8();
1724
+ return bounded5({
1725
+ op,
1726
+ operationId: ids.operationId,
1727
+ messageId: ids.messageId,
1728
+ credential,
1729
+ expectedHead: parseMlsDevGroupHead(input2.expectedHead),
1730
+ preconditions: parseMlsDevApplicationPreconditions(input2.preconditions),
1731
+ interaction,
1732
+ body: Object.freeze(body),
1733
+ seal
1734
+ });
1735
+ }
1736
+ if (op === "open_secret_answer") {
1737
+ const input2 = readMlsDataRecord(value, ["op", "requestId", "responderId", "responderDeviceId", "sealed"]), sealed = readMlsDataRecord(input2.sealed, ["enc", "ciphertext"]);
1738
+ const binding3 = parseMlsDevInteractionBinding({ role: "response", requestId: input2.requestId, agentId: input2.responderId });
1739
+ return bounded5({
1740
+ op,
1741
+ requestId: binding3.requestId,
1742
+ responderId: id4(input2.responderId),
1743
+ responderDeviceId: requireMlsUuid(input2.responderDeviceId),
1744
+ sealed: Object.freeze({ enc: encoded4(sealed.enc, 32), ciphertext: sealedCiphertext(sealed.ciphertext) })
1055
1745
  });
1056
1746
  }
1057
1747
  if (op === "discard") {
1058
1748
  const input2 = readMlsDataRecord(value, ["op", "operationId", "control"]);
1059
- return bounded5({ op, operationId: id3(input2.operationId), control: parseMlsDevGroupControl(input2.control) });
1749
+ return bounded5({ op, operationId: id4(input2.operationId), control: parseMlsDevGroupControl(input2.control) });
1060
1750
  }
1061
1751
  if (op === "finalize") {
1062
1752
  const input2 = readMlsDataRecord(value, ["op", "accepted"]);
1063
1753
  return bounded5({ op, accepted: parseMlsDevGroupAcceptedControl(input2.accepted) });
1064
1754
  }
1065
1755
  if (op === "join" || op === "process") {
1066
- const input2 = readMlsDataRecord(value, op === "join" ? ["op", "credential", "accepted", "keyPackageId"] : ["op", "credential", "accepted"]);
1067
- const common2 = { credential: token(input2.credential), accepted: parseMlsDevGroupAcceptedControl(input2.accepted) };
1756
+ const input2 = readMlsDataRecord(value, op === "join" ? ["op", "credential", "accepted", "receiptProof", "feedOrdinal", "keyPackageId"] : ["op", "credential", "accepted", "receiptProof", "feedOrdinal"]);
1757
+ const common2 = {
1758
+ credential: token(input2.credential),
1759
+ accepted: parseMlsDevGroupAcceptedControl(input2.accepted),
1760
+ receiptProof: parseMlsDevFeedReceiptProof(input2.receiptProof),
1761
+ feedOrdinal: requireMlsInteger(input2.feedOrdinal, 1)
1762
+ };
1068
1763
  if (op === "join") {
1069
1764
  if (common2.accepted.control.kind !== "add")
1070
- invalid6();
1765
+ invalid8();
1071
1766
  return bounded5({ op, ...common2, keyPackageId: requireMlsUuid(input2.keyPackageId) });
1072
1767
  }
1073
1768
  return bounded5({ op, ...common2 });
1074
1769
  }
1075
1770
  const common = ["op", "operationId", "credential", "preconditions"];
1076
1771
  const input = readMlsDataRecord(value, op === "create" ? common : op === "add" ? [...common, "expectedHead", "keyPackageClaim"] : op === "remove" ? [...common, "expectedHead", "removedDeviceId"] : []);
1077
- const fields = { operationId: id3(input.operationId), credential: token(input.credential), preconditions: parseMlsDevGroupPreconditions(input.preconditions) };
1772
+ const fields2 = { operationId: id4(input.operationId), credential: token(input.credential), preconditions: parseMlsDevGroupPreconditions(input.preconditions) };
1078
1773
  if (op === "create") {
1079
- if (fields.preconditions.targetAdmissionId !== null)
1080
- invalid6();
1081
- return bounded5({ op, ...fields });
1774
+ if (fields2.preconditions.targetAdmissionId !== null)
1775
+ invalid8();
1776
+ return bounded5({ op, ...fields2 });
1082
1777
  }
1083
- if (fields.preconditions.targetAdmissionId === null)
1084
- invalid6();
1778
+ if (fields2.preconditions.targetAdmissionId === null)
1779
+ invalid8();
1085
1780
  const expectedHead = parseMlsDevGroupHead(input.expectedHead);
1086
1781
  if (op === "add")
1087
1782
  return bounded5({
1088
1783
  op,
1089
- ...fields,
1784
+ ...fields2,
1090
1785
  expectedHead,
1091
1786
  keyPackageClaim: parseMlsDevKeyPackageClaimReceipt(input.keyPackageClaim)
1092
1787
  });
1093
1788
  if (op === "remove")
1094
1789
  return bounded5({
1095
1790
  op,
1096
- ...fields,
1791
+ ...fields2,
1097
1792
  expectedHead,
1098
1793
  removedDeviceId: requireMlsUuid(input.removedDeviceId)
1099
1794
  });
1100
- return invalid6();
1795
+ return invalid8();
1101
1796
  });
1102
1797
  }
1103
1798
  __name(parseMlsDevGroupCommand, "parseMlsDevGroupCommand");
1104
1799
  function parseMlsDevGroupPreparation(value) {
1105
- return boundary5(() => {
1800
+ return boundary7(() => {
1106
1801
  const input = readMlsDataRecord(value, ["wrappedState", "payload"]);
1107
1802
  if (typeof input.wrappedState !== "string" || input.wrappedState.length > MLS_DEV_GROUP_WRAPPED_MAX_BYTES || !input.wrappedState.startsWith("v1:"))
1108
- invalid6();
1803
+ invalid8();
1109
1804
  const body = input.wrappedState.slice(3);
1110
1805
  if (body.length < 40 || body.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(body))
1111
- invalid6();
1806
+ invalid8();
1112
1807
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1113
1808
  if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0 || !body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0)
1114
- invalid6();
1809
+ invalid8();
1115
1810
  const kind = Object.getOwnPropertyDescriptor(input.payload ?? {}, "kind");
1116
1811
  if (!kind || !Object.hasOwn(kind, "value"))
1117
- invalid6();
1812
+ invalid8();
1118
1813
  let payload;
1119
1814
  if (kind.value === "application") {
1120
- const fields = readMlsDataRecord(input.payload, ["kind", "envelope"]);
1121
- payload = Object.freeze({ kind: "application", envelope: parseMlsDevApplicationEnvelope(fields.envelope) });
1815
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "envelope", ...present(input.payload, ["payload"])]);
1816
+ payload = Object.freeze({
1817
+ kind: "application",
1818
+ envelope: parseMlsDevApplicationEnvelope(fields2.envelope),
1819
+ ...fields2.payload === void 0 ? {} : { payload: plaintextJson(fields2.payload) }
1820
+ });
1821
+ } else if (kind.value === "item") {
1822
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "payload", "feedOrdinal"]);
1823
+ const ids = parseMlsDevTextPayload({
1824
+ version: 1,
1825
+ kind: "text",
1826
+ conversationId: "validation",
1827
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1828
+ messageId: fields2.messageId,
1829
+ operationId: fields2.operationId,
1830
+ senderDeviceId: fields2.senderDeviceId,
1831
+ text: "x"
1832
+ });
1833
+ payload = Object.freeze({
1834
+ kind: "item",
1835
+ messageId: ids.messageId,
1836
+ operationId: ids.operationId,
1837
+ senderDeviceId: ids.senderDeviceId,
1838
+ payload: plaintextJson(fields2.payload),
1839
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1840
+ });
1122
1841
  } else if (kind.value === "text") {
1123
- const fields = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "text", "feedOrdinal"]);
1124
- const text3 = parseMlsDevTextPayload({
1842
+ const extras = present(input.payload, ["replyTo", "mentions"]);
1843
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "text", "feedOrdinal", ...extras]);
1844
+ const text5 = parseMlsDevTextPayload({
1125
1845
  version: 1,
1126
1846
  kind: "text",
1127
1847
  conversationId: "validation",
1128
1848
  groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1129
- messageId: fields.messageId,
1130
- operationId: fields.operationId,
1131
- senderDeviceId: fields.senderDeviceId,
1132
- text: fields.text
1849
+ messageId: fields2.messageId,
1850
+ operationId: fields2.operationId,
1851
+ senderDeviceId: fields2.senderDeviceId,
1852
+ text: fields2.text,
1853
+ ...pick(fields2, extras)
1133
1854
  });
1134
1855
  payload = Object.freeze({
1135
1856
  kind: "text",
1136
- messageId: text3.messageId,
1137
- operationId: text3.operationId,
1138
- senderDeviceId: text3.senderDeviceId,
1139
- text: text3.text,
1140
- feedOrdinal: requireMlsInteger(fields.feedOrdinal, 1)
1857
+ messageId: text5.messageId,
1858
+ operationId: text5.operationId,
1859
+ senderDeviceId: text5.senderDeviceId,
1860
+ text: text5.text,
1861
+ ...textExtras(text5),
1862
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1863
+ });
1864
+ } else if (kind.value === "interaction_application") {
1865
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "envelope", "payload"]);
1866
+ payload = Object.freeze({ kind: "interaction_application", envelope: parseMlsDevApplicationEnvelope(fields2.envelope), payload: plaintextJson(fields2.payload) });
1867
+ if (!payload.envelope.interaction)
1868
+ invalid8();
1869
+ } else if (kind.value === "interaction") {
1870
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "payload", "feedOrdinal"]);
1871
+ const ids = parseMlsDevTextPayload({
1872
+ version: 1,
1873
+ kind: "text",
1874
+ conversationId: "validation",
1875
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1876
+ messageId: fields2.messageId,
1877
+ operationId: fields2.operationId,
1878
+ senderDeviceId: fields2.senderDeviceId,
1879
+ text: "x"
1880
+ });
1881
+ payload = Object.freeze({
1882
+ kind: "interaction",
1883
+ messageId: ids.messageId,
1884
+ operationId: ids.operationId,
1885
+ senderDeviceId: ids.senderDeviceId,
1886
+ payload: plaintextJson(fields2.payload),
1887
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1141
1888
  });
1889
+ } else if (kind.value === "invalid") {
1890
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "feedOrdinal"]);
1891
+ const ids = parseMlsDevTextPayload({
1892
+ version: 1,
1893
+ kind: "text",
1894
+ conversationId: "validation",
1895
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1896
+ messageId: fields2.messageId,
1897
+ operationId: fields2.operationId,
1898
+ senderDeviceId: fields2.senderDeviceId,
1899
+ text: "x"
1900
+ });
1901
+ payload = Object.freeze({
1902
+ kind: "invalid",
1903
+ messageId: ids.messageId,
1904
+ operationId: ids.operationId,
1905
+ senderDeviceId: ids.senderDeviceId,
1906
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1907
+ });
1908
+ } else if (kind.value === "secret") {
1909
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "requestId", "text"]);
1910
+ const binding3 = parseMlsDevInteractionBinding({ role: "withdraw", requestId: fields2.requestId });
1911
+ if (typeof fields2.text !== "string" || !fields2.text.trim() || [...fields2.text].length > MLS_DEV_INTERACTION_LIMITS.text || new TextDecoder("utf-8", { fatal: true }).decode(utf84.encode(fields2.text)) !== fields2.text)
1912
+ invalid8();
1913
+ payload = Object.freeze({ kind: "secret", requestId: binding3.requestId, text: fields2.text });
1142
1914
  } else if (kind.value === "control") {
1143
- const fields = readMlsDataRecord(input.payload, ["kind", "control"]);
1144
- payload = Object.freeze({ kind: "control", control: parseMlsDevGroupControl(fields.control) });
1915
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "control"]);
1916
+ payload = Object.freeze({ kind: "control", control: parseMlsDevGroupControl(fields2.control) });
1145
1917
  } else if (kind.value === "discarded") {
1146
- const fields = readMlsDataRecord(input.payload, ["kind", "operationId", "head"]);
1147
- payload = Object.freeze({ kind: "discarded", operationId: id3(fields.operationId), head: fields.head === null ? null : parseMlsDevGroupHead(fields.head) });
1918
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "operationId", "head"]);
1919
+ payload = Object.freeze({ kind: "discarded", operationId: id4(fields2.operationId), head: fields2.head === null ? null : parseMlsDevGroupHead(fields2.head) });
1148
1920
  } else {
1149
- const fields = readMlsDataRecord(input.payload, ["kind", "head", "roster", "removed", "consumedKeyPackageId"]);
1921
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "head", "roster", "removed", "consumedKeyPackageId"]);
1150
1922
  payload = Object.freeze({
1151
- kind: requireMlsLiteral(fields.kind, "applied"),
1152
- head: parseMlsDevGroupHead(fields.head),
1153
- roster: parseMlsDevGroupRoster(fields.roster),
1154
- removed: boolean2(fields.removed),
1155
- consumedKeyPackageId: fields.consumedKeyPackageId === null ? null : requireMlsUuid(fields.consumedKeyPackageId)
1923
+ kind: requireMlsLiteral(fields2.kind, "applied"),
1924
+ head: parseMlsDevGroupHead(fields2.head),
1925
+ roster: parseMlsDevGroupRoster(fields2.roster),
1926
+ removed: boolean3(fields2.removed),
1927
+ consumedKeyPackageId: fields2.consumedKeyPackageId === null ? null : requireMlsUuid(fields2.consumedKeyPackageId)
1156
1928
  });
1157
1929
  }
1158
1930
  return bounded5({ wrappedState: input.wrappedState, payload }, MLS_DEV_GROUP_PREPARATION_MAX_BYTES);
@@ -1162,9 +1934,25 @@ __name(parseMlsDevGroupPreparation, "parseMlsDevGroupPreparation");
1162
1934
 
1163
1935
  // ../backend-contracts/src/mlsDevApplication.ts
1164
1936
  var MLS_DEV_TEXT_PROTOCOL = "canon.mls.dev-text.v1";
1937
+ var MLS_DEV_TEXT_PROTOCOL_V2 = "canon.mls.dev-text.v2";
1938
+ var MLS_DEV_TEXT_PROTOCOL_V3 = "canon.mls.dev-text.v3";
1939
+ var MLS_DEV_TEXT_PROTOCOLS = [MLS_DEV_TEXT_PROTOCOL, MLS_DEV_TEXT_PROTOCOL_V2, MLS_DEV_TEXT_PROTOCOL_V3];
1940
+ function isMlsDevTextProtocol(value) {
1941
+ return MLS_DEV_TEXT_PROTOCOLS.some((protocol) => protocol === value);
1942
+ }
1943
+ __name(isMlsDevTextProtocol, "isMlsDevTextProtocol");
1944
+ function mlsDevProtocolCarriesCards(value) {
1945
+ return value === MLS_DEV_TEXT_PROTOCOL_V2 || value === MLS_DEV_TEXT_PROTOCOL_V3;
1946
+ }
1947
+ __name(mlsDevProtocolCarriesCards, "mlsDevProtocolCarriesCards");
1948
+ var MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS = 1024;
1949
+ var MLS_DEV_MENTIONS_MAX = 32;
1950
+ var MLS_DEV_INTERACTION_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,160}$/;
1951
+ var MLS_DEV_INTERACTION_KINDS = ["approval", "question", "secret"];
1165
1952
  var MLS_DEV_APPLICATION_TLS_MAX_BYTES = 256 * 1024;
1166
1953
  var MLS_DEV_APPLICATION_MAX_BYTES = 384 * 1024;
1167
1954
  var MLS_DEV_TEXT_MAX_BYTES = 32 * 1024;
1955
+ var MLS_DEV_ITEM_TYPES = ["image", "video", "audio", "file"];
1168
1956
  var MlsDevApplicationValidationError = class extends Error {
1169
1957
  static {
1170
1958
  __name(this, "MlsDevApplicationValidationError");
@@ -1174,125 +1962,245 @@ var MlsDevApplicationValidationError = class extends Error {
1174
1962
  super("INVALID_MLS_DEV_APPLICATION");
1175
1963
  this.name = "MlsDevApplicationValidationError";
1176
1964
  }
1177
- };
1178
- var utf84 = new TextEncoder();
1179
- function invalid7() {
1965
+ };
1966
+ var utf85 = new TextEncoder();
1967
+ function invalid9() {
1180
1968
  throw new MlsDevApplicationValidationError();
1181
1969
  }
1182
- __name(invalid7, "invalid");
1183
- function boundary6(read) {
1970
+ __name(invalid9, "invalid");
1971
+ function boundary8(read) {
1184
1972
  try {
1185
1973
  return read();
1186
1974
  } catch {
1187
- return invalid7();
1975
+ return invalid9();
1188
1976
  }
1189
1977
  }
1190
- __name(boundary6, "boundary");
1978
+ __name(boundary8, "boundary");
1191
1979
  function bounded6(value) {
1192
- if (utf84.encode(JSON.stringify(value)).length > MLS_DEV_APPLICATION_MAX_BYTES)
1193
- invalid7();
1980
+ if (utf85.encode(JSON.stringify(value)).length > MLS_DEV_APPLICATION_MAX_BYTES)
1981
+ invalid9();
1194
1982
  return Object.freeze(value);
1195
1983
  }
1196
1984
  __name(bounded6, "bounded");
1197
- function id4(value) {
1985
+ function id5(value) {
1198
1986
  if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..")
1199
- invalid7();
1987
+ invalid9();
1200
1988
  return value;
1201
1989
  }
1202
- __name(id4, "id");
1990
+ __name(id5, "id");
1991
+ function isMlsDevMessageId(value) {
1992
+ return typeof value === "string" && /^[A-Za-z0-9_.:~-]{1,200}$/.test(value) && value !== "." && value !== ".." && !value.startsWith("membership-");
1993
+ }
1994
+ __name(isMlsDevMessageId, "isMlsDevMessageId");
1203
1995
  function messageId(value) {
1204
- const result = id4(value);
1205
- if (result.startsWith("membership-"))
1206
- invalid7();
1207
- return result;
1996
+ if (!isMlsDevMessageId(value))
1997
+ invalid9();
1998
+ return value;
1208
1999
  }
1209
2000
  __name(messageId, "messageId");
1210
- function encoded4(value, bytes) {
2001
+ function interactionId2(value) {
2002
+ if (typeof value !== "string" || !MLS_DEV_INTERACTION_ID_PATTERN.test(value) || value === "." || value === "..")
2003
+ invalid9();
2004
+ return value;
2005
+ }
2006
+ __name(interactionId2, "interactionId");
2007
+ function parseMlsDevInteractionBinding(value) {
2008
+ return boundary8(() => {
2009
+ const role = value && typeof value === "object" ? Object.getOwnPropertyDescriptor(value, "role") : void 0;
2010
+ if (!role || !Object.hasOwn(role, "value"))
2011
+ invalid9();
2012
+ if (role.value === "request") {
2013
+ const input2 = readMlsDataRecord(value, ["role", "requestId", "kind", "responderIds", "expiresAtMs"]);
2014
+ if (typeof input2.kind !== "string" || !MLS_DEV_INTERACTION_KINDS.includes(input2.kind))
2015
+ invalid9();
2016
+ const responders = input2.responderIds;
2017
+ if (!Array.isArray(responders) || Object.getPrototypeOf(responders) !== Array.prototype || responders.length !== 1 || Reflect.ownKeys(Object.getOwnPropertyDescriptors(responders)).length !== 2)
2018
+ invalid9();
2019
+ const only = Object.getOwnPropertyDescriptor(responders, 0);
2020
+ if (!only || !only.enumerable || !Object.hasOwn(only, "value"))
2021
+ invalid9();
2022
+ const expiresAtMs = requireMlsInteger(input2.expiresAtMs, 1);
2023
+ return Object.freeze({
2024
+ role: "request",
2025
+ requestId: interactionId2(input2.requestId),
2026
+ kind: input2.kind,
2027
+ responderIds: Object.freeze([id5(only.value)]),
2028
+ expiresAtMs
2029
+ });
2030
+ }
2031
+ if (role.value === "response") {
2032
+ const input2 = readMlsDataRecord(value, ["role", "requestId", "agentId"]);
2033
+ return Object.freeze({ role: "response", requestId: interactionId2(input2.requestId), agentId: id5(input2.agentId) });
2034
+ }
2035
+ const input = readMlsDataRecord(value, ["role", "requestId"]);
2036
+ return Object.freeze({ role: requireMlsLiteral(input.role, "withdraw"), requestId: interactionId2(input.requestId) });
2037
+ });
2038
+ }
2039
+ __name(parseMlsDevInteractionBinding, "parseMlsDevInteractionBinding");
2040
+ function encoded5(value, bytes) {
1211
2041
  decodeCanonicalMlsBase64Url(value, bytes);
1212
2042
  return value;
1213
2043
  }
1214
- __name(encoded4, "encoded");
2044
+ __name(encoded5, "encoded");
1215
2045
  function parseMlsDevApplicationWire(value) {
1216
- return boundary6(() => {
2046
+ return boundary8(() => {
1217
2047
  if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_APPLICATION_TLS_MAX_BYTES * 4 / 3))
1218
- invalid7();
2048
+ invalid9();
1219
2049
  const bytes = Math.floor(value.length * 3 / 4);
1220
2050
  if (bytes > MLS_DEV_APPLICATION_TLS_MAX_BYTES || value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value))
1221
- invalid7();
2051
+ invalid9();
1222
2052
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
1223
2053
  if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0)
1224
- invalid7();
2054
+ invalid9();
1225
2055
  return value;
1226
2056
  });
1227
2057
  }
1228
2058
  __name(parseMlsDevApplicationWire, "parseMlsDevApplicationWire");
1229
2059
  function parseMlsDevApplicationPreconditions(value) {
1230
- return boundary6(() => {
2060
+ return boundary8(() => {
1231
2061
  const input = readMlsDataRecord(value, ["membershipRevision", "admissionId"]);
1232
- return Object.freeze({ membershipRevision: requireMlsInteger(input.membershipRevision), admissionId: id4(input.admissionId) });
2062
+ return Object.freeze({ membershipRevision: requireMlsInteger(input.membershipRevision), admissionId: id5(input.admissionId) });
1233
2063
  });
1234
2064
  }
1235
2065
  __name(parseMlsDevApplicationPreconditions, "parseMlsDevApplicationPreconditions");
1236
2066
  var bindingFields = ["version", "environmentId", "conversationId", "groupId", "messageId", "senderCredential", "expectedHead", "preconditions"];
2067
+ var interactionBindingFields = [...bindingFields, "interaction"];
1237
2068
  function binding(input) {
1238
- parseMlsDevCredentialToken(input.senderCredential);
2069
+ const environmentId = requireMlsEnvironmentId(input.environmentId);
2070
+ if (parseMlsDevCredentialToken(input.senderCredential).unsigned.claims.device.environmentId !== environmentId) invalid9();
1239
2071
  return {
1240
2072
  version: requireMlsLiteral(input.version, 1),
1241
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
1242
- conversationId: id4(input.conversationId),
1243
- groupId: encoded4(input.groupId, 32),
2073
+ environmentId,
2074
+ conversationId: id5(input.conversationId),
2075
+ groupId: encoded5(input.groupId, 32),
1244
2076
  messageId: messageId(input.messageId),
1245
2077
  senderCredential: input.senderCredential,
1246
2078
  expectedHead: parseMlsDevGroupHead(input.expectedHead),
1247
- preconditions: parseMlsDevApplicationPreconditions(input.preconditions)
2079
+ preconditions: parseMlsDevApplicationPreconditions(input.preconditions),
2080
+ ...Object.hasOwn(input, "interaction") ? { interaction: parseMlsDevInteractionBinding(input.interaction) } : {}
1248
2081
  };
1249
2082
  }
1250
2083
  __name(binding, "binding");
2084
+ function fields(value, extra) {
2085
+ return readMlsDataRecord(value, [...bindingFields, ...extra], [...interactionBindingFields, ...extra]);
2086
+ }
2087
+ __name(fields, "fields");
1251
2088
  function parseMlsDevApplicationEnvelope(value) {
1252
- return boundary6(() => {
1253
- const input = readMlsDataRecord(value, [...bindingFields, "ciphertext", "proof"]);
1254
- return bounded6({ ...binding(input), ciphertext: parseMlsDevApplicationWire(input.ciphertext), proof: encoded4(input.proof, 64) });
2089
+ return boundary8(() => {
2090
+ const input = fields(value, ["ciphertext", "proof"]);
2091
+ return bounded6({ ...binding(input), ciphertext: parseMlsDevApplicationWire(input.ciphertext), proof: encoded5(input.proof, 64) });
1255
2092
  });
1256
2093
  }
1257
2094
  __name(parseMlsDevApplicationEnvelope, "parseMlsDevApplicationEnvelope");
1258
2095
  function parseMlsDevApplicationReceipt(value) {
1259
- return boundary6(() => {
2096
+ return boundary8(() => {
1260
2097
  const input = readMlsDataRecord(value, ["version", "authorization", "operationId", "conversationId", "groupId", "messageId", "feedOrdinal", "head", "acceptedAtMs", "envelopeHash"]);
1261
2098
  return bounded6({
1262
2099
  version: requireMlsLiteral(input.version, 1),
1263
2100
  authorization: requireMlsLiteral(input.authorization, "encrypted_text_only"),
1264
- operationId: id4(input.operationId),
1265
- conversationId: id4(input.conversationId),
1266
- groupId: encoded4(input.groupId, 32),
2101
+ operationId: id5(input.operationId),
2102
+ conversationId: id5(input.conversationId),
2103
+ groupId: encoded5(input.groupId, 32),
1267
2104
  messageId: messageId(input.messageId),
1268
2105
  feedOrdinal: requireMlsInteger(input.feedOrdinal, 1),
1269
2106
  head: parseMlsDevGroupHead(input.head),
1270
2107
  acceptedAtMs: requireMlsInteger(input.acceptedAtMs),
1271
- envelopeHash: encoded4(input.envelopeHash, 32)
2108
+ envelopeHash: encoded5(input.envelopeHash, 32)
1272
2109
  });
1273
2110
  });
1274
2111
  }
1275
2112
  __name(parseMlsDevApplicationReceipt, "parseMlsDevApplicationReceipt");
2113
+ function text2(value) {
2114
+ if (typeof value !== "string" || !value.trim() || utf85.encode(value).length > MLS_DEV_TEXT_MAX_BYTES || new TextDecoder("utf-8", { fatal: true }).decode(utf85.encode(value)) !== value)
2115
+ invalid9();
2116
+ return value;
2117
+ }
2118
+ __name(text2, "text");
2119
+ function textExtras2(value) {
2120
+ const extras = {};
2121
+ if (Object.hasOwn(value, "replyTo")) {
2122
+ const reply = readMlsDataRecord(value.replyTo, ["messageId", "quote"]);
2123
+ if ([...text2(reply.quote)].length > MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS)
2124
+ invalid9();
2125
+ extras.replyTo = Object.freeze({ messageId: messageId(reply.messageId), quote: reply.quote });
2126
+ }
2127
+ if (Object.hasOwn(value, "mentions")) {
2128
+ const mentions = value.mentions;
2129
+ if (!Array.isArray(mentions) || mentions.length < 1 || mentions.length > MLS_DEV_MENTIONS_MAX || new Set(mentions).size !== mentions.length)
2130
+ invalid9();
2131
+ extras.mentions = Object.freeze(mentions.map(id5));
2132
+ }
2133
+ return extras;
2134
+ }
2135
+ __name(textExtras2, "textExtras");
2136
+ var optionalKeys = /* @__PURE__ */ __name((value, keys2) => value && typeof value === "object" ? keys2.filter((key) => Object.hasOwn(value, key)) : [], "optionalKeys");
1276
2137
  function parseMlsDevTextPayload(value) {
1277
- return boundary6(() => {
1278
- const input = readMlsDataRecord(value, ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId", "text"]);
1279
- if (typeof input.text !== "string" || !input.text.trim() || utf84.encode(input.text).length > MLS_DEV_TEXT_MAX_BYTES || new TextDecoder("utf-8", { fatal: true }).decode(utf84.encode(input.text)) !== input.text)
1280
- invalid7();
2138
+ return boundary8(() => {
2139
+ const input = readMlsDataRecord(value, ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId", "text", ...optionalKeys(value, ["replyTo", "mentions"])]);
1281
2140
  return bounded6({
1282
2141
  version: requireMlsLiteral(input.version, 1),
1283
2142
  kind: requireMlsLiteral(input.kind, "text"),
1284
- conversationId: id4(input.conversationId),
1285
- groupId: encoded4(input.groupId, 32),
2143
+ conversationId: id5(input.conversationId),
2144
+ groupId: encoded5(input.groupId, 32),
1286
2145
  messageId: messageId(input.messageId),
1287
- operationId: id4(input.operationId),
2146
+ operationId: id5(input.operationId),
1288
2147
  senderDeviceId: requireMlsUuid(input.senderDeviceId),
1289
- text: input.text
2148
+ text: text2(input.text),
2149
+ ...textExtras2(input)
1290
2150
  });
1291
2151
  });
1292
2152
  }
1293
2153
  __name(parseMlsDevTextPayload, "parseMlsDevTextPayload");
1294
- function framed(domain3, value, operationId) {
1295
- const operation = utf84.encode(id4(operationId)), json = utf84.encode(JSON.stringify(value)), prefix = utf84.encode(domain3);
2154
+ var itemFields = ["type", "uploadId", "url", "mimeType", "sizeBytes", "fileName", "width", "height", "durationMs", "thumbnailUrl", "caption", "replyTo", "mentions"];
2155
+ function httpsUrl(value) {
2156
+ if (typeof value !== "string" || value.length > 2048) invalid9();
2157
+ const url = boundary8(() => new URL(value));
2158
+ if (url.protocol !== "https:" || url.username || url.password) invalid9();
2159
+ return value;
2160
+ }
2161
+ __name(httpsUrl, "httpsUrl");
2162
+ var dimension = /* @__PURE__ */ __name((value) => requireMlsInteger(value, 0) <= 1e5 ? value : invalid9(), "dimension");
2163
+ function item(value) {
2164
+ const input = readMlsDataRecord(value, ["type", "uploadId", "url", "mimeType", "sizeBytes", ...optionalKeys(value, itemFields.slice(5))]);
2165
+ if (!MLS_DEV_ITEM_TYPES.some((type) => type === input.type) || typeof input.mimeType !== "string" || !/^[a-z0-9.+-]{1,64}\/[a-z0-9.+-]{1,128}$/i.test(input.mimeType))
2166
+ invalid9();
2167
+ if (input.fileName !== void 0 && (typeof input.fileName !== "string" || !input.fileName.trim() || [...input.fileName].length > 240))
2168
+ invalid9();
2169
+ return Object.freeze({
2170
+ type: input.type,
2171
+ uploadId: requireMlsUuid(input.uploadId),
2172
+ url: httpsUrl(input.url),
2173
+ mimeType: input.mimeType,
2174
+ sizeBytes: requireMlsInteger(input.sizeBytes, 1),
2175
+ ...input.fileName === void 0 ? {} : { fileName: input.fileName },
2176
+ ...Object.fromEntries(["width", "height", "durationMs"].filter((key) => input[key] !== void 0).map((key) => [key, key === "durationMs" ? requireMlsInteger(input[key], 0) : dimension(input[key])])),
2177
+ ...input.thumbnailUrl === void 0 ? {} : { thumbnailUrl: httpsUrl(input.thumbnailUrl) },
2178
+ ...input.caption === void 0 ? {} : { caption: text2(input.caption) },
2179
+ ...textExtras2(input)
2180
+ });
2181
+ }
2182
+ __name(item, "item");
2183
+ function parseMlsDevItemPayload(value) {
2184
+ return boundary8(() => {
2185
+ const input = readMlsDataRecord(value, ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId", "item"]);
2186
+ const payload = {
2187
+ version: requireMlsLiteral(input.version, 1),
2188
+ kind: requireMlsLiteral(input.kind, "item"),
2189
+ conversationId: id5(input.conversationId),
2190
+ groupId: encoded5(input.groupId, 32),
2191
+ messageId: messageId(input.messageId),
2192
+ operationId: id5(input.operationId),
2193
+ senderDeviceId: requireMlsUuid(input.senderDeviceId),
2194
+ item: item(input.item)
2195
+ };
2196
+ if (utf85.encode(JSON.stringify(payload)).length > MLS_DEV_TEXT_MAX_BYTES)
2197
+ invalid9();
2198
+ return bounded6(payload);
2199
+ });
2200
+ }
2201
+ __name(parseMlsDevItemPayload, "parseMlsDevItemPayload");
2202
+ function framed(domain4, value, operationId) {
2203
+ const operation = utf85.encode(id5(operationId)), json = utf85.encode(JSON.stringify(value)), prefix = utf85.encode(domain4);
1296
2204
  const result = new Uint8Array(prefix.length + 8 + operation.length + json.length), view = new DataView(result.buffer);
1297
2205
  let offset = 0;
1298
2206
  result.set(prefix, offset);
@@ -1308,7 +2216,7 @@ function framed(domain3, value, operationId) {
1308
2216
  }
1309
2217
  __name(framed, "framed");
1310
2218
  function encodeMlsDevApplicationEnvelopeHash(value, operationId) {
1311
- return boundary6(() => framed("canon.mls.dev-application-envelope.v1\0", parseMlsDevApplicationEnvelope(value), operationId));
2219
+ return boundary8(() => framed("canon.mls.dev-application-envelope.v1\0", parseMlsDevApplicationEnvelope(value), operationId));
1312
2220
  }
1313
2221
  __name(encodeMlsDevApplicationEnvelopeHash, "encodeMlsDevApplicationEnvelopeHash");
1314
2222
 
@@ -1329,12 +2237,6 @@ var RUNTIME_CARD_FIELD_TYPES = [
1329
2237
  "searchSelect",
1330
2238
  "lineItems"
1331
2239
  ];
1332
- var RUNTIME_CARD_LIMITS = {
1333
- detailsRows: 32,
1334
- lineItemRows: 50,
1335
- lineItemColumns: 8,
1336
- searchSelectChoices: 100
1337
- };
1338
2240
  var RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES = [
1339
2241
  "text",
1340
2242
  "number",
@@ -1526,7 +2428,7 @@ var VERB_NATIVE_METADATA_KEYS = [
1526
2428
  "handles"
1527
2429
  ];
1528
2430
  var VERB_NATIVE_STRING_KEYS = VERB_NATIVE_METADATA_KEYS.filter(
1529
- (key2) => key2 !== "handles"
2431
+ (key) => key !== "handles"
1530
2432
  );
1531
2433
  var RUNTIME_CORRELATION_VALUE_PATTERN = new RegExp(
1532
2434
  VERB_ID_PATTERNS.runtimeCorrelationValue
@@ -1728,7 +2630,7 @@ var sessionRuleDef = {
1728
2630
  };
1729
2631
  var runtimeCardDef = {
1730
2632
  type: "object",
1731
- description: `ENVELOPE-ONLY validation of a canon.card.v1 document: block structures are NOT checked here. Tool bindings MUST compose the full document schema via getVerbInputSchema(verb, { cardSchema: RUNTIME_CARD_JSON_SCHEMA_V1 }) so models cannot produce envelope-valid cards the platform rejects. Full document contract: @canonmsg/rich-cards RUNTIME_CARD_JSON_SCHEMA_V1 ($id https://canonmsg.com/schemas/canon.card.v1.json) \u2014 authoring caps title 120 / fallbackText 500 / blocks 24. Server envelope acceptance (interactionCard.ts): <= ${VERB_LIMITS.cardEnvelopeBytes} bytes serialized, title <= ${VERB_LIMITS.cardServerTitleChars}, fallbackText <= ${VERB_LIMITS.cardServerFallbackTextChars}, blocks <= ${VERB_LIMITS.cardServerBlocks}; no secret-bearing top-level keys.`,
2633
+ description: `ENVELOPE-ONLY validation of a canon.card.v1 document: block structures are NOT checked here. Full document contract: @canonmsg/rich-cards RUNTIME_CARD_JSON_SCHEMA_V1 ($id https://canonmsg.com/schemas/canon.card.v1.json) \u2014 authoring caps title 120 / fallbackText 500 / blocks 24. Server envelope acceptance (interactionCard.ts): <= ${VERB_LIMITS.cardEnvelopeBytes} bytes serialized, title <= ${VERB_LIMITS.cardServerTitleChars}, fallbackText <= ${VERB_LIMITS.cardServerFallbackTextChars}, blocks <= ${VERB_LIMITS.cardServerBlocks}; no secret-bearing top-level keys.`,
1732
2634
  required: ["schema", "title", "fallbackText", "blocks"],
1733
2635
  additionalProperties: true,
1734
2636
  properties: {
@@ -1861,6 +2763,20 @@ var send_to_result = {
1861
2763
  sessionSelection: { type: "string" }
1862
2764
  }
1863
2765
  },
2766
+ {
2767
+ type: "object",
2768
+ required: ["status", "conversationId", "messageId", "openingText"],
2769
+ additionalProperties: true,
2770
+ description: "The room is encrypted, so Canon stored no opening text: the sender sends it encrypted under messageId.",
2771
+ properties: {
2772
+ status: { const: "opened" },
2773
+ conversationId: { type: "string" },
2774
+ messageId: { type: "string" },
2775
+ openingText: { const: "deferred" },
2776
+ created: { type: "boolean" },
2777
+ reused: { type: "boolean" }
2778
+ }
2779
+ },
1864
2780
  {
1865
2781
  type: "object",
1866
2782
  required: ["status", "requestId"],
@@ -1871,6 +2787,12 @@ var send_to_result = {
1871
2787
  deferredIntentId: {
1872
2788
  type: ["string", "null"],
1873
2789
  description: "Present when the send is deferred until the contact request resolves."
2790
+ },
2791
+ conversationId: { type: "string" },
2792
+ messageId: { type: "string" },
2793
+ openingText: {
2794
+ const: "deferred",
2795
+ description: "The room is encrypted, so Canon stored no opening text: the sender sends it encrypted under messageId."
1874
2796
  }
1875
2797
  }
1876
2798
  },
@@ -2755,9 +3677,9 @@ function splitTurnMetadata(metadata) {
2755
3677
  if (!metadata || typeof metadata !== "object") return { turn: void 0, rest: void 0 };
2756
3678
  const turn = {};
2757
3679
  const rest = {};
2758
- for (const [key2, value] of Object.entries(metadata)) {
2759
- if (TURN_KEYS.includes(key2)) turn[key2] = value;
2760
- else rest[key2] = value;
3680
+ for (const [key, value] of Object.entries(metadata)) {
3681
+ if (TURN_KEYS.includes(key)) turn[key] = value;
3682
+ else rest[key] = value;
2761
3683
  }
2762
3684
  return {
2763
3685
  turn: Object.keys(turn).length ? turn : void 0,
@@ -2765,10 +3687,10 @@ function splitTurnMetadata(metadata) {
2765
3687
  };
2766
3688
  }
2767
3689
  __name(splitTurnMetadata, "splitTurnMetadata");
2768
- function compact(record4) {
3690
+ function compact(record5) {
2769
3691
  const out = {};
2770
- for (const [key2, value] of Object.entries(record4)) {
2771
- if (value !== void 0) out[key2] = value;
3692
+ for (const [key, value] of Object.entries(record5)) {
3693
+ if (value !== void 0) out[key] = value;
2772
3694
  }
2773
3695
  return out;
2774
3696
  }
@@ -2948,12 +3870,12 @@ function parseDirectConversationSelection(value) {
2948
3870
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2949
3871
  throw new Error("selection must be an object");
2950
3872
  }
2951
- const record4 = value;
2952
- if (record4.mode === "latest_or_new" || record4.mode === "new") {
2953
- return { mode: record4.mode };
3873
+ const record5 = value;
3874
+ if (record5.mode === "latest_or_new" || record5.mode === "new") {
3875
+ return { mode: record5.mode };
2954
3876
  }
2955
- if (record4.mode === "specific") {
2956
- const conversationId = typeof record4.conversationId === "string" ? record4.conversationId.trim() : "";
3877
+ if (record5.mode === "specific") {
3878
+ const conversationId = typeof record5.conversationId === "string" ? record5.conversationId.trim() : "";
2957
3879
  if (!conversationId) throw new Error("selection.conversationId is required");
2958
3880
  return { mode: "specific", conversationId };
2959
3881
  }
@@ -2978,10 +3900,10 @@ function record(value) {
2978
3900
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
2979
3901
  }
2980
3902
  __name(record, "record");
2981
- function text(value, max) {
3903
+ function text3(value, max) {
2982
3904
  return typeof value === "string" && value.length > 0 && value.length <= max ? value : void 0;
2983
3905
  }
2984
- __name(text, "text");
3906
+ __name(text3, "text");
2985
3907
  function member(value, choices) {
2986
3908
  return choices.includes(value) ? value : void 0;
2987
3909
  }
@@ -3016,19 +3938,19 @@ function normalizeDispatch(value) {
3016
3938
  return primitive ? { kind: "primitive", primitive } : void 0;
3017
3939
  }
3018
3940
  case "control": {
3019
- const controlId = text(dispatch.controlId, 128);
3020
- return controlId ? defined({ kind: "control", controlId, value: text(dispatch.value, 1024) }) : void 0;
3941
+ const controlId = text3(dispatch.controlId, 128);
3942
+ return controlId ? defined({ kind: "control", controlId, value: text3(dispatch.value, 1024) }) : void 0;
3021
3943
  }
3022
3944
  case "text_passthrough": {
3023
- const template = text(dispatch.template, 2048);
3945
+ const template = text3(dispatch.template, 2048);
3024
3946
  return template ? { kind: "text_passthrough", template } : void 0;
3025
3947
  }
3026
3948
  case "compose": {
3027
- const content = text(dispatch.text, 2048);
3949
+ const content = text3(dispatch.text, 2048);
3028
3950
  return content ? { kind: "compose", text: content } : void 0;
3029
3951
  }
3030
3952
  case "open_details":
3031
- return defined({ kind: "open_details", target: text(dispatch.target, 128) });
3953
+ return defined({ kind: "open_details", target: text3(dispatch.target, 128) });
3032
3954
  default:
3033
3955
  return void 0;
3034
3956
  }
@@ -3036,21 +3958,21 @@ function normalizeDispatch(value) {
3036
3958
  __name(normalizeDispatch, "normalizeDispatch");
3037
3959
  function normalizeArgument(value) {
3038
3960
  const arg = record(value);
3039
- const id6 = text(arg.id, 128);
3040
- const label = text(arg.label, 160);
3961
+ const id7 = text3(arg.id, 128);
3962
+ const label = text3(arg.label, 160);
3041
3963
  const kind = member(arg.kind, ["string", "enum", "boolean"]);
3042
- if (!id6 || !label || !kind) return void 0;
3043
- if (["required", "captureRemaining"].some((key2) => arg[key2] !== void 0 && typeof arg[key2] !== "boolean")) return void 0;
3964
+ if (!id7 || !label || !kind) return void 0;
3965
+ if (["required", "captureRemaining"].some((key) => arg[key] !== void 0 && typeof arg[key] !== "boolean")) return void 0;
3044
3966
  if (arg.choices !== void 0 && !Array.isArray(arg.choices)) return void 0;
3045
3967
  const choices = Array.isArray(arg.choices) ? arg.choices.slice(0, 128).flatMap((value2) => {
3046
3968
  const choice = record(value2);
3047
- const entry = text(choice.value, 1024);
3048
- const label2 = text(choice.label, 160);
3049
- return entry && label2 ? [defined({ value: entry, label: label2, description: text(choice.description, 1024) })] : [];
3969
+ const entry = text3(choice.value, 1024);
3970
+ const label2 = text3(choice.label, 160);
3971
+ return entry && label2 ? [defined({ value: entry, label: label2, description: text3(choice.description, 1024) })] : [];
3050
3972
  }) : void 0;
3051
3973
  if (kind === "enum" && !choices?.length) return void 0;
3052
3974
  return defined({
3053
- id: id6,
3975
+ id: id7,
3054
3976
  label,
3055
3977
  kind,
3056
3978
  choices,
@@ -3064,15 +3986,15 @@ function normalizePublicRuntimeCommands(value) {
3064
3986
  const seenIds = /* @__PURE__ */ new Set();
3065
3987
  const seenAliases = /* @__PURE__ */ new Set();
3066
3988
  const result = [];
3067
- for (const item of value.slice(0, MAX_PUBLIC_RUNTIME_COMMANDS)) {
3068
- const command = record(item);
3069
- const id6 = text(command.id, 128);
3070
- const label = text(command.label, 160);
3989
+ for (const item2 of value.slice(0, MAX_PUBLIC_RUNTIME_COMMANDS)) {
3990
+ const command = record(item2);
3991
+ const id7 = text3(command.id, 128);
3992
+ const label = text3(command.label, 160);
3071
3993
  const dispatch = normalizeDispatch(command.dispatch);
3072
- if (!id6 || !label || !dispatch || seenIds.has(id6) || command.visibility === "hidden" || command.sensitive === true) continue;
3073
- if (["ownerOnly", "sensitive"].some((key2) => command[key2] !== void 0 && typeof command[key2] !== "boolean")) continue;
3074
- if (["aliases", "args", "placements", "availability"].some((key2) => command[key2] !== void 0 && !Array.isArray(command[key2]))) continue;
3075
- const rawAliases = Array.isArray(command.aliases) && command.aliases.length ? command.aliases : [id6];
3994
+ if (!id7 || !label || !dispatch || seenIds.has(id7) || command.visibility === "hidden" || command.sensitive === true) continue;
3995
+ if (["ownerOnly", "sensitive"].some((key) => command[key] !== void 0 && typeof command[key] !== "boolean")) continue;
3996
+ if (["aliases", "args", "placements", "availability"].some((key) => command[key] !== void 0 && !Array.isArray(command[key]))) continue;
3997
+ const rawAliases = Array.isArray(command.aliases) && command.aliases.length ? command.aliases : [id7];
3076
3998
  const aliases = [...new Set(rawAliases.slice(0, 8).flatMap((value2) => {
3077
3999
  const alias = typeof value2 === "string" && value2.length <= 128 ? normalizeRuntimeCommandAlias(value2) : null;
3078
4000
  return alias && /^[A-Za-z0-9:_-]+$/.test(alias) && !seenAliases.has(alias.toLowerCase()) ? [alias] : [];
@@ -3080,20 +4002,20 @@ function normalizePublicRuntimeCommands(value) {
3080
4002
  if (!aliases.length) continue;
3081
4003
  const args = Array.isArray(command.args) ? command.args.slice(0, 12).map(normalizeArgument) : void 0;
3082
4004
  if (args?.some((arg) => !arg) || Array.isArray(command.args) && command.args.length > 12) continue;
3083
- seenIds.add(id6);
4005
+ seenIds.add(id7);
3084
4006
  aliases.forEach((alias) => seenAliases.add(alias.toLowerCase()));
3085
4007
  result.push(defined({
3086
- id: id6,
4008
+ id: id7,
3087
4009
  label,
3088
4010
  aliases,
3089
4011
  dispatch,
3090
4012
  args,
3091
- description: text(command.description, 1024),
4013
+ description: text3(command.description, 1024),
3092
4014
  category: member(command.category, ["plan", "turn", "session", "runtime", "details", "skill", "custom"]),
3093
4015
  placements: members(command.placements, ["composer_slash", "command_palette", "session_strip"]),
3094
4016
  availability: members(command.availability, ["idle", "busy", "busy_with_queue", "waiting_input", "always"]),
3095
4017
  ownerOnly: typeof command.ownerOnly === "boolean" ? command.ownerOnly : void 0,
3096
- disabledReason: text(command.disabledReason, 1024),
4018
+ disabledReason: text3(command.disabledReason, 1024),
3097
4019
  trailingTextBehavior: member(command.trailingTextBehavior, ["ignore", "send_as_prompt"]),
3098
4020
  primitive: member(command.primitive, PRIMITIVES),
3099
4021
  tier: member(command.tier, ["primary", "detail", "diagnostic"])
@@ -3127,14 +4049,14 @@ function normalizePublicRuntimeFacts(value) {
3127
4049
  const seen = /* @__PURE__ */ new Set();
3128
4050
  return value.slice(0, 16).flatMap((entry) => {
3129
4051
  const fact = record(entry);
3130
- const id6 = text(fact.id, 64);
3131
- const group = id6 && Object.hasOwn(PUBLIC_RUNTIME_FACT_GROUPS, id6) ? PUBLIC_RUNTIME_FACT_GROUPS[id6] : void 0;
3132
- const label = text(fact.label, 80);
3133
- const content = text(fact.value, 512);
3134
- if (!id6 || !group || !label || !content || seen.has(id6) || fact.sensitive === true || fact.visibility === "hidden") return [];
3135
- seen.add(id6);
4052
+ const id7 = text3(fact.id, 64);
4053
+ const group = id7 && Object.hasOwn(PUBLIC_RUNTIME_FACT_GROUPS, id7) ? PUBLIC_RUNTIME_FACT_GROUPS[id7] : void 0;
4054
+ const label = text3(fact.label, 80);
4055
+ const content = text3(fact.value, 512);
4056
+ if (!id7 || !group || !label || !content || seen.has(id7) || fact.sensitive === true || fact.visibility === "hidden") return [];
4057
+ seen.add(id7);
3136
4058
  return [defined({
3137
- id: id6,
4059
+ id: id7,
3138
4060
  group,
3139
4061
  label,
3140
4062
  value: content,
@@ -3147,13 +4069,8 @@ function normalizePublicRuntimeFacts(value) {
3147
4069
  }
3148
4070
  __name(normalizePublicRuntimeFacts, "normalizePublicRuntimeFacts");
3149
4071
 
3150
- // ../backend-contracts/src/workSessions.ts
3151
- var WORK_SESSION_REQUEST_TTL_MS = 5 * 6e4;
3152
- var SETTINGS_KEYS = ["projectId", "modelId", "reasoningEffort", "permissionMode", "executionMode"];
3153
- var DETAIL_FIELDS = [...SETTINGS_KEYS, "projectLabel", "workingDirectory", "branch", "worktreePath", "sandbox", "approvalPolicy", "nativeThreadBehavior"];
3154
-
3155
4072
  // ../backend-contracts/src/endpointContentPolicy.ts
3156
- var MLS_DEV_UNSUPPORTED_CONTENT_ACTIONS = ["delete_message", "forward_message"];
4073
+ var MLS_DEV_UNSUPPORTED_CONTENT_ACTIONS = ["forward_message"];
3157
4074
  var ENDPOINT_CONTENT_ACTIONS = [
3158
4075
  "mls_application",
3159
4076
  "mls_group_control",
@@ -3161,8 +4078,6 @@ var ENDPOINT_CONTENT_ACTIONS = [
3161
4078
  "append_artifact_command",
3162
4079
  "retain_artifact_asset",
3163
4080
  "sync_phone_contacts",
3164
- "request_work_session",
3165
- "resolve_work_session_request",
3166
4081
  "update_agent_behavior_policy",
3167
4082
  "update_conversation_agent_behavior_policy",
3168
4083
  "send_message",
@@ -3215,6 +4130,8 @@ var ENDPOINT_CONTENT_ACTIONS = [
3215
4130
  var ENDPOINT_CONTENT_FUNCTION_QUERIES = [
3216
4131
  "mls_group_feed",
3217
4132
  "mls_group_controls",
4133
+ "mls_group_admissions",
4134
+ "mls_interactions",
3218
4135
  "list_artifacts",
3219
4136
  "get_artifact_log",
3220
4137
  "get_artifact_asset",
@@ -3222,9 +4139,6 @@ var ENDPOINT_CONTENT_FUNCTION_QUERIES = [
3222
4139
  "get_unread_summary",
3223
4140
  "peek_runtime_signal",
3224
4141
  "list_runtime_primitives",
3225
- "get_work_session_catalog",
3226
- "get_work_session_details",
3227
- "get_work_session_request",
3228
4142
  "get_agent_behavior_policy",
3229
4143
  "get_conversation_agent_behavior_policy",
3230
4144
  "get_ephemeral",
@@ -3246,7 +4160,8 @@ var ENDPOINT_CONTENT_FUNCTION_QUERIES = [
3246
4160
  "get_media_message",
3247
4161
  "get_voice_session",
3248
4162
  "get_image_generation",
3249
- "get_image_generation_status"
4163
+ "get_image_generation_status",
4164
+ "same_owner_agents"
3250
4165
  ];
3251
4166
  var ENDPOINT_CONTENT_QUERIES = [...ENDPOINT_CONTENT_FUNCTION_QUERIES, "admit_messages"];
3252
4167
  var ENDPOINT_CONTENT_EPHEMERALS = [
@@ -3360,7 +4275,8 @@ var actionRouting = {
3360
4275
  send_message: ["conversationId", "messageId", "replyTo", "mentions.*"],
3361
4276
  delete_message: ["conversationId", "messageId"],
3362
4277
  forward_message: ["sourceConversationId", "targetConversationId", "messageId"],
3363
- react: ["conversationId", "messageId"],
4278
+ // A reaction is an action on a message's public stub, so its emoji is server-visible in encrypted rooms too (ruling 3).
4279
+ react: ["conversationId", "messageId", "emoji"],
3364
4280
  send_contextual_message: ["conversationId"],
3365
4281
  create_interaction: ["conversationId", "requestId", "inputId", "approvalId", "cardId", "planId", "responseUserId"],
3366
4282
  consume_interaction: ["conversationId", "inputId", "approvalId", "cardId", "planId"],
@@ -3381,13 +4297,19 @@ var actionRouting = {
3381
4297
  set_block: ["targetUserId"],
3382
4298
  save_contact: ["contactUserId"],
3383
4299
  remove_contact: ["contactId", "contactUserId"],
3384
- session_control: ["conversationId", "agentId"],
4300
+ // `signal.type` is the closed Stop family (interrupt, stop_and_drop, new_session) the server must read to deliver it;
4301
+ // a runtime `primitive` (commands, arguments) stays private, so it remains refused in encrypted rooms.
4302
+ session_control: ["conversationId", "agentId", "signal.type"],
3385
4303
  approve_contact_request: ["requestId"],
3386
4304
  reject_contact_request: ["requestId"],
3387
4305
  cancel_direct_request: ["requestId"],
3388
4306
  update_message_disposition: ["conversationId", "messageId"],
3389
- create_upload: ["conversationId"],
4307
+ // An encrypted room's item uploads its bytes as in a plaintext room (they are not end-to-end encrypted, payload v3
4308
+ // §4): the type, size and display hints are public; its file name and caption ride only inside the item.
4309
+ create_upload: ["conversationId", "mimeType", "sizeBytes", "width", "height", "durationMs"],
3390
4310
  finalize_upload: ["uploadId"],
4311
+ // An encrypted item's application names its uploads beside the ciphertext, for Canon to retain on acceptance.
4312
+ mls_application: ["mediaUploadIds.*"],
3391
4313
  delete_upload: ["uploadId"],
3392
4314
  retry_video_processing: ["uploadId"],
3393
4315
  stage_media_message: ["conversationId", "messageId", "files.*.fileId", "contentVersion", ...preparedRoutingPaths.map((path) => `preparedContent.${path}`)],
@@ -3395,19 +4317,18 @@ var actionRouting = {
3395
4317
  renew_media_message_upload: ["conversationId", "messageId", "fileId", "generation"],
3396
4318
  finalize_memo_stream: ["conversationId", "streamId"],
3397
4319
  abort_memo_stream: ["streamId"],
3398
- create_voice_session: ["conversationId"],
4320
+ create_voice_session: ["conversationId", "media"],
3399
4321
  join_voice_session: ["conversationId", "sessionId"],
3400
4322
  decline_voice_session: ["conversationId", "sessionId"],
3401
4323
  end_voice_session: ["conversationId", "sessionId"],
3402
4324
  consume_runtime_signal: ["conversationId", "expectedSignalId"],
3403
4325
  consume_runtime_primitive: ["conversationId", "requestId", "expectedRevision"],
3404
4326
  generate_image: ["conversationId", "requestId"],
3405
- request_work_session: ["conversationId", "agentId", "requestId"],
3406
- resolve_work_session_request: ["requestId"],
3407
4327
  update_agent_behavior_policy: ["agentId"],
3408
4328
  update_conversation_agent_behavior_policy: ["conversationId", "agentId"]
3409
4329
  };
3410
4330
  var queryRouting = {
4331
+ mls_interactions: ["version", "conversationId"],
3411
4332
  list_artifacts: ["conversationId", "cursor", "limit"],
3412
4333
  get_artifact_log: ["conversationId", "artifactId", "afterSequence", "cursor", "limit"],
3413
4334
  get_artifact_asset: ["conversationId", "artifactId", "assetId"],
@@ -3433,12 +4354,19 @@ var queryRouting = {
3433
4354
  get_media_message: ["conversationId", "messageId", "installationId"],
3434
4355
  get_voice_session: ["conversationId", "sessionId"],
3435
4356
  get_image_generation: ["requestId"],
3436
- get_work_session_catalog: ["agentId"],
3437
- get_work_session_details: ["agentId", "conversationId"],
3438
- get_work_session_request: ["requestId"],
4357
+ same_owner_agents: ["agentIds.*"],
3439
4358
  get_agent_behavior_policy: ["agentId"],
3440
4359
  get_conversation_agent_behavior_policy: ["conversationId", "agentId"]
3441
4360
  };
4361
+ var ENDPOINT_TURN_PRESENCE_STATES = ["thinking", "waiting_input", "interrupted", "idle"];
4362
+ var timestamp = /* @__PURE__ */ __name((value) => value === null || Number.isSafeInteger(value) && value >= 0, "timestamp");
4363
+ var turnPresence = {
4364
+ state: /* @__PURE__ */ __name((value) => ENDPOINT_TURN_PRESENCE_STATES.includes(value), "state"),
4365
+ // `turn-` and 32 random hex digits per encrypted turn: never the runner's own turn id, which seeds its cards' request ids.
4366
+ turnId: /* @__PURE__ */ __name((value) => value === null || typeof value === "string" && /^turn-[0-9a-f]{32}$/.test(value), "turnId"),
4367
+ openedAt: timestamp,
4368
+ turnUpdatedAt: timestamp
4369
+ };
3442
4370
  var transientRouting = {
3443
4371
  create_memo_stream: ["conversationId", "streamId"],
3444
4372
  append_memo_chunk: ["streamId"],
@@ -3478,7 +4406,7 @@ function endpointOperationRequestRetention(action, body, envelope) {
3478
4406
  if (action !== "respond_interaction") return "journal";
3479
4407
  if (envelope && Object.keys(envelope).length > 0) return "memory";
3480
4408
  const routing = ["kind", "conversationId", "agentId", "requestId"];
3481
- const hasOnly = /* @__PURE__ */ __name((fields) => Object.keys(body).every((field) => fields.includes(field)), "hasOnly");
4409
+ const hasOnly = /* @__PURE__ */ __name((fields2) => Object.keys(body).every((field) => fields2.includes(field)), "hasOnly");
3482
4410
  if (routing.some((field) => body[field] !== void 0 && typeof body[field] !== "string")) return "memory";
3483
4411
  if ((body.kind === "input" || body.kind === "card") && hasOnly([...routing, "status", "actionId"])) {
3484
4412
  if (!["submitted", "cancelled"].includes(String(body.status)) || body.actionId !== void 0 && typeof body.actionId !== "string") return "memory";
@@ -3501,8 +4429,8 @@ function endpointOperationRequestRetention(action, body, envelope) {
3501
4429
  __name(endpointOperationRequestRetention, "endpointOperationRequestRetention");
3502
4430
  function endpointContentBoundary(lane, name, payload) {
3503
4431
  if (!namesForLane[lane]?.includes(name)) throw new EndpointContentPolicyError(lane, name);
3504
- const record4 = payload && typeof payload === "object" ? payload : void 0;
3505
- if (lane === "query.request" && name === "get_ephemeral" && record4 && !ENDPOINT_CONTENT_EPHEMERAL_FAMILIES.includes(record4.family)) {
4432
+ const record5 = payload && typeof payload === "object" ? payload : void 0;
4433
+ if (lane === "query.request" && name === "get_ephemeral" && record5 && !ENDPOINT_CONTENT_EPHEMERAL_FAMILIES.includes(record5.family)) {
3506
4434
  throw new EndpointContentPolicyError(lane, `${name}/unknown-family`);
3507
4435
  }
3508
4436
  const requestRoutingPaths = (actionRouting[name] ?? []).flatMap((field) => [`body.value.${field}`, `envelope.${field}`]);
@@ -3510,7 +4438,7 @@ function endpointContentBoundary(lane, name, payload) {
3510
4438
  if (path.some((part) => secretSegments.has(part))) return "restricted-secret";
3511
4439
  if (lane === "operation.request" && ["respond_interaction", "sync_phone_contacts"].includes(name) && matches(path, "preparedContent.payload")) return "restricted-secret";
3512
4440
  if (lane === "operation.request" && ["respond_interaction", "sync_phone_contacts"].includes(name) && path[0] === "body" && path[1] === "value" && !publicMatch(path, requestRoutingPaths)) return "restricted-secret";
3513
- if (lane === "operation.receipt" && path[0] === "result" && (["consume_interaction", "respond_interaction"].includes(name) || record4?.resultReference?.kind === "interaction")) return "restricted-secret";
4441
+ if (lane === "operation.receipt" && path[0] === "result" && (["consume_interaction", "respond_interaction"].includes(name) || record5?.resultReference?.kind === "interaction")) return "restricted-secret";
3514
4442
  let selected = payload;
3515
4443
  for (const part of path) selected = selected && typeof selected === "object" && Object.hasOwn(selected, part) ? selected[part] : void 0;
3516
4444
  if (selected !== null && typeof selected === "object") return "private-content";
@@ -3519,8 +4447,8 @@ function endpointContentBoundary(lane, name, payload) {
3519
4447
  if (name === "respond_interaction" && path[0] === "body" && path[1] === "value") return "restricted-secret";
3520
4448
  if (name === "sync_phone_contacts" && path[0] === "body" && path[1] === "value") return "restricted-secret";
3521
4449
  if (name === "verb_execute") {
3522
- const wire3 = record4?.body?.value;
3523
- const spec = VERB_WIRE_ENVELOPE_FIELDS[wire3?.verb];
4450
+ const wire4 = record5?.body?.value;
4451
+ const spec = VERB_WIRE_ENVELOPE_FIELDS[wire4?.verb];
3524
4452
  if (path[0] === "body" && path[1] === "value") {
3525
4453
  if (path.length === 3 && ["wire", "verb"].includes(path[2])) return "public-metadata";
3526
4454
  if (path[2] === "envelope" && spec) {
@@ -3532,7 +4460,7 @@ function endpointContentBoundary(lane, name, payload) {
3532
4460
  }
3533
4461
  } else if (lane === "operation.receipt") {
3534
4462
  if (publicMatch(path, [...protocolPaths, "status", "createdAt", "updatedAt", "error.code", "error.status", "error.retryable", "error.retryAfterMs", "resultError.code", "resultError.status", "resultReference.kind", "resultReference.conversationId", "resultReference.artifactId", "resultReference.assetId", "resultReference.uploadId", "resultReference.sessionId", "resultReference.requestId"])) return "public-metadata";
3535
- if (path[0] === "result" && (name === "consume_interaction" || name === "respond_interaction" || record4?.resultReference?.kind === "interaction")) return "restricted-secret";
4463
+ if (path[0] === "result" && (name === "consume_interaction" || name === "respond_interaction" || record5?.resultReference?.kind === "interaction")) return "restricted-secret";
3536
4464
  } else if (lane === "query.request") {
3537
4465
  if (publicMatch(path, queryRouting[name] ?? [])) return "public-metadata";
3538
4466
  } else if (lane === "query.result" || lane === "ephemeral.result") {
@@ -3540,6 +4468,7 @@ function endpointContentBoundary(lane, name, payload) {
3540
4468
  if (name === "get_ephemeral" && path[0] === "value") return "private-content";
3541
4469
  } else if (lane === "ephemeral.request") {
3542
4470
  if (publicMatch(path, transientRouting[name] ?? [])) return "public-metadata";
4471
+ if (name === "publish_turn" && path.length === 1 && Object.hasOwn(turnPresence, path[0]) && turnPresence[path[0]](selected)) return "public-metadata";
3543
4472
  } else if (lane === "event") {
3544
4473
  if (publicMatch(path, eventRouting(name))) return "public-metadata";
3545
4474
  }
@@ -3563,12 +4492,12 @@ var PreparedContentError = class extends Error {
3563
4492
  __name(this, "PreparedContentError");
3564
4493
  }
3565
4494
  };
3566
- function invalid8() {
4495
+ function invalid10() {
3567
4496
  throw new PreparedContentError("INVALID_PREPARED_CONTENT");
3568
4497
  }
3569
- __name(invalid8, "invalid");
4498
+ __name(invalid10, "invalid");
3570
4499
  var record2 = /* @__PURE__ */ __name((value) => !!value && typeof value === "object" && !Array.isArray(value), "record");
3571
- var keys = /* @__PURE__ */ __name((value, allowed) => Object.keys(value).every((key2) => allowed.includes(key2)), "keys");
4500
+ var keys = /* @__PURE__ */ __name((value, allowed) => Object.keys(value).every((key) => allowed.includes(key)), "keys");
3572
4501
  var revision = /* @__PURE__ */ __name((value) => Number.isSafeInteger(value) && value >= 0, "revision");
3573
4502
  var blobIdentity = /* @__PURE__ */ __name((value) => typeof value === "string" && value.length > 0 && value.length <= 1024 && !/[\u0000-\u001f]/.test(value), "blobIdentity");
3574
4503
  var identity = /* @__PURE__ */ __name((value) => typeof value === "string" && ENDPOINT_ID_PATTERN.test(value), "identity");
@@ -3579,33 +4508,33 @@ function canonicalEndpointJson(value) {
3579
4508
  function encode(input) {
3580
4509
  if (input === null || typeof input !== "object") return JSON.stringify(input);
3581
4510
  if (Array.isArray(input)) return `[${input.map(encode).join(",")}]`;
3582
- const object2 = input;
3583
- return `{${Object.keys(object2).sort().map((key2) => `${JSON.stringify(key2)}:${encode(object2[key2])}`).join(",")}}`;
4511
+ const object = input;
4512
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${encode(object[key])}`).join(",")}}`;
3584
4513
  }
3585
4514
  __name(encode, "encode");
3586
4515
  return encode(normalized);
3587
4516
  }
3588
4517
  __name(canonicalEndpointJson, "canonicalEndpointJson");
3589
4518
  function validateMetadata(value) {
3590
- if (!record2(value)) invalid8();
4519
+ if (!record2(value)) invalid10();
3591
4520
  if (value.version !== PREPARED_CONTENT_VERSION) throw new PreparedContentError("UNSUPPORTED_PREPARED_CONTENT_VERSION");
3592
4521
  if (value.codec !== PREPARED_JSON_CODEC) throw new PreparedContentError("UNSUPPORTED_PREPARED_CONTENT_CODEC");
3593
- if (!keys(value, ["version", "context", "codec", "payload", "blobs", "expected"])) invalid8();
4522
+ if (!keys(value, ["version", "context", "codec", "payload", "blobs", "expected"])) invalid10();
3594
4523
  const context = value.context;
3595
- if (!record2(context) || !keys(context, ["action", "conversationId", "messageId"]) || typeof context.action !== "string" || !ENDPOINT_ACTION_PATTERN.test(context.action) || context.conversationId !== void 0 && !identity(context.conversationId) || context.messageId !== void 0 && !identity(context.messageId)) invalid8();
4524
+ if (!record2(context) || !keys(context, ["action", "conversationId", "messageId"]) || typeof context.action !== "string" || !ENDPOINT_ACTION_PATTERN.test(context.action) || context.conversationId !== void 0 && !identity(context.conversationId) || context.messageId !== void 0 && !identity(context.messageId)) invalid10();
3596
4525
  const expected = value.expected;
3597
- if (!record2(expected) || !keys(expected, ["installationGeneration", "protocolRevision", "admission"]) || !revision(expected.installationGeneration) || !revision(expected.protocolRevision)) invalid8();
4526
+ if (!record2(expected) || !keys(expected, ["installationGeneration", "protocolRevision", "admission"]) || !revision(expected.installationGeneration) || !revision(expected.protocolRevision)) invalid10();
3598
4527
  if (expected.admission !== void 0) {
3599
4528
  const admission = expected.admission;
3600
- if (!record2(admission) || !keys(admission, ["conversationId", "membershipRevision", "admissionId", "targetAdmissionId"]) || ["conversationId", "admissionId", "targetAdmissionId"].some((key2) => admission[key2] !== void 0 && !identity(admission[key2])) || admission.membershipRevision !== void 0 && !revision(admission.membershipRevision) || context.conversationId !== void 0 && admission.conversationId !== void 0 && admission.conversationId !== context.conversationId) invalid8();
4529
+ if (!record2(admission) || !keys(admission, ["conversationId", "membershipRevision", "admissionId", "targetAdmissionId"]) || ["conversationId", "admissionId", "targetAdmissionId"].some((key) => admission[key] !== void 0 && !identity(admission[key])) || admission.membershipRevision !== void 0 && !revision(admission.membershipRevision) || context.conversationId !== void 0 && admission.conversationId !== void 0 && admission.conversationId !== context.conversationId) invalid10();
3601
4530
  }
3602
- if (!Array.isArray(value.blobs)) invalid8();
4531
+ if (!Array.isArray(value.blobs)) invalid10();
3603
4532
  const ids = /* @__PURE__ */ new Set();
3604
4533
  for (const [index, blob] of value.blobs.entries()) {
3605
- if (!record2(blob) || !keys(blob, ["id", "index"]) || !blobIdentity(blob.id) || blob.index !== index || ids.has(blob.id)) invalid8();
4534
+ if (!record2(blob) || !keys(blob, ["id", "index"]) || !blobIdentity(blob.id) || blob.index !== index || ids.has(blob.id)) invalid10();
3606
4535
  ids.add(blob.id);
3607
4536
  }
3608
- if (typeof value.payload !== "string") invalid8();
4537
+ if (typeof value.payload !== "string") invalid10();
3609
4538
  }
3610
4539
  __name(validateMetadata, "validateMetadata");
3611
4540
  function decodePreparedJsonContent(value) {
@@ -3614,18 +4543,18 @@ function decodePreparedJsonContent(value) {
3614
4543
  try {
3615
4544
  decoded = JSON.parse(value.payload);
3616
4545
  } catch {
3617
- invalid8();
4546
+ invalid10();
3618
4547
  }
3619
- if (!record2(decoded) || !keys(decoded, ["body", "envelope"]) || !record2(decoded.body) || decoded.envelope !== void 0 && !record2(decoded.envelope)) invalid8();
3620
- if (canonicalEndpointJson(decoded) !== value.payload) invalid8();
4548
+ if (!record2(decoded) || !keys(decoded, ["body", "envelope"]) || !record2(decoded.body) || decoded.envelope !== void 0 && !record2(decoded.envelope)) invalid10();
4549
+ if (canonicalEndpointJson(decoded) !== value.payload) invalid10();
3621
4550
  const { body, envelope } = decoded;
3622
4551
  if (endpointOperationRequestRetention(value.context.action, body, envelope) === "memory") {
3623
4552
  throw new PreparedContentError("PREPARED_CONTENT_MEMORY_ONLY");
3624
4553
  }
3625
4554
  const effective = { ...body, ...envelope };
3626
- for (const key2 of ["conversationId", "messageId"]) {
3627
- const bound = value.context[key2];
3628
- if (bound !== void 0 && effective[key2] !== void 0 && effective[key2] !== bound) invalid8();
4555
+ for (const key of ["conversationId", "messageId"]) {
4556
+ const bound = value.context[key];
4557
+ if (bound !== void 0 && effective[key] !== void 0 && effective[key] !== bound) invalid10();
3629
4558
  }
3630
4559
  return envelope === void 0 ? { body } : { body, envelope };
3631
4560
  }
@@ -3655,7 +4584,7 @@ function prepareJsonContent(input) {
3655
4584
  }
3656
4585
  __name(prepareJsonContent, "prepareJsonContent");
3657
4586
  function logicalMediaBlobId(conversationId, messageId2, index) {
3658
- if (!identity(conversationId) || !identity(messageId2) || !revision(index)) invalid8();
4587
+ if (!identity(conversationId) || !identity(messageId2) || !revision(index)) invalid10();
3659
4588
  return JSON.stringify([conversationId, messageId2, index]);
3660
4589
  }
3661
4590
  __name(logicalMediaBlobId, "logicalMediaBlobId");
@@ -3671,10 +4600,130 @@ function isEndpointOperationReceipt(value) {
3671
4600
  }
3672
4601
  __name(isEndpointOperationReceipt, "isEndpointOperationReceipt");
3673
4602
 
4603
+ // ../backend-contracts/src/connectorRelay.ts
4604
+ var CONNECTOR_RELAY_INSTALLATION_PREFIX = "canon-relay:";
4605
+ var CONNECTOR_RELAY_INSTALLATION_PATTERN = /^canon-relay:[0-9a-f]{40}$/;
4606
+ function isConnectorRelayInstallation(installationId) {
4607
+ return typeof installationId === "string" && installationId.startsWith(CONNECTOR_RELAY_INSTALLATION_PREFIX);
4608
+ }
4609
+ __name(isConnectorRelayInstallation, "isConnectorRelayInstallation");
4610
+ var CONNECTOR_RELAY_CREDENTIAL_PATTERN = /^canon_relay_[A-Za-z0-9_-]{43}$/;
4611
+ function isConnectorRelayCredential(value) {
4612
+ return typeof value === "string" && CONNECTOR_RELAY_CREDENTIAL_PATTERN.test(value);
4613
+ }
4614
+ __name(isConnectorRelayCredential, "isConnectorRelayCredential");
4615
+ var CONNECTOR_RELAY_INPUT_ID_PATTERN = /^relay:[0-9a-f]{40}$/;
4616
+ var CONNECTOR_RELAY_MAX_BODY_BYTES = 256 * 1024;
4617
+ var CONNECTOR_RELAY_MAX_TEXT_BYTES = MLS_DEV_TEXT_MAX_BYTES;
4618
+ var CONNECTOR_RELAY_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
4619
+ var CONNECTOR_RELAY_ANSWER_WITHIN_MS = 7e3;
4620
+ function connectorRelayResponseBytes(value) {
4621
+ return new TextEncoder().encode(JSON.stringify(value)).length;
4622
+ }
4623
+ __name(connectorRelayResponseBytes, "connectorRelayResponseBytes");
4624
+ var ConnectorRelayRequestError = class extends Error {
4625
+ static {
4626
+ __name(this, "ConnectorRelayRequestError");
4627
+ }
4628
+ name = "ConnectorRelayRequestError";
4629
+ };
4630
+ function invalid11(what) {
4631
+ throw new ConnectorRelayRequestError(`Invalid relay request: ${what}`);
4632
+ }
4633
+ __name(invalid11, "invalid");
4634
+ function record3(value, required, optional = []) {
4635
+ if (!value || typeof value !== "object" || Array.isArray(value)) invalid11("expected an object");
4636
+ const result = value;
4637
+ for (const key of Object.keys(result)) if (!required.includes(key) && !optional.includes(key)) invalid11(`unexpected ${key}`);
4638
+ for (const key of required) if (!Object.hasOwn(result, key)) invalid11(`missing ${key}`);
4639
+ return result;
4640
+ }
4641
+ __name(record3, "record");
4642
+ function id6(value, what, pattern = ENDPOINT_ID_PATTERN) {
4643
+ if (typeof value !== "string" || !pattern.test(value)) invalid11(what);
4644
+ return value;
4645
+ }
4646
+ __name(id6, "id");
4647
+ function doc(value, what) {
4648
+ if (typeof value !== "string" || !value || value.length > 200 || value.includes("/")) invalid11(what);
4649
+ return value;
4650
+ }
4651
+ __name(doc, "doc");
4652
+ var room = /* @__PURE__ */ __name((value) => doc(value, "conversationId"), "room");
4653
+ function text4(value) {
4654
+ if (typeof value !== "string" || !value.trim() || new TextEncoder().encode(value).length > CONNECTOR_RELAY_MAX_TEXT_BYTES) invalid11("text");
4655
+ return value;
4656
+ }
4657
+ __name(text4, "text");
4658
+ function limit(value) {
4659
+ if (value === void 0) return void 0;
4660
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > 100) invalid11("limit");
4661
+ return value;
4662
+ }
4663
+ __name(limit, "limit");
4664
+ function parseConnectorRelayRequest(value) {
4665
+ const body = record3(value, ["version", "agentId", "grantId", "op", "args"]);
4666
+ if (body.version !== 1) invalid11("version");
4667
+ const head = { version: 1, agentId: doc(body.agentId, "agentId"), grantId: id6(body.grantId, "grantId") };
4668
+ switch (body.op) {
4669
+ case "pending": {
4670
+ const args = record3(body.args, ["conversationId"], ["limit"]);
4671
+ return { ...head, op: "pending", args: { conversationId: room(args.conversationId), ...args.limit === void 0 ? {} : { limit: limit(args.limit) } } };
4672
+ }
4673
+ case "claim": {
4674
+ const args = record3(body.args, ["inputId", "requestId"]);
4675
+ return { ...head, op: "claim", args: { inputId: id6(args.inputId, "inputId", CONNECTOR_RELAY_INPUT_ID_PATTERN), requestId: id6(args.requestId, "requestId") } };
4676
+ }
4677
+ case "reply": {
4678
+ const args = record3(body.args, ["inputId", "requestId", "text"]);
4679
+ return { ...head, op: "reply", args: {
4680
+ inputId: id6(args.inputId, "inputId", CONNECTOR_RELAY_INPUT_ID_PATTERN),
4681
+ requestId: id6(args.requestId, "requestId"),
4682
+ text: text4(args.text)
4683
+ } };
4684
+ }
4685
+ case "settle": {
4686
+ const args = record3(body.args, ["inputId", "requestId", "outcome"]);
4687
+ if (!["completed", "no_reply", "failed"].includes(args.outcome)) invalid11("outcome");
4688
+ return { ...head, op: "settle", args: {
4689
+ inputId: id6(args.inputId, "inputId", CONNECTOR_RELAY_INPUT_ID_PATTERN),
4690
+ requestId: id6(args.requestId, "requestId"),
4691
+ outcome: args.outcome
4692
+ } };
4693
+ }
4694
+ case "read": {
4695
+ const args = record3(body.args, ["conversationId"], ["limit", "before"]);
4696
+ if (args.before !== void 0 && (typeof args.before !== "string" || !/^[1-9][0-9]{0,15}$/.test(args.before))) invalid11("before");
4697
+ return { ...head, op: "read", args: {
4698
+ conversationId: room(args.conversationId),
4699
+ ...args.limit === void 0 ? {} : { limit: limit(args.limit) },
4700
+ ...args.before === void 0 ? {} : { before: args.before }
4701
+ } };
4702
+ }
4703
+ case "send": {
4704
+ const args = record3(body.args, ["conversationId", "messageId", "text"]);
4705
+ return { ...head, op: "send", args: { conversationId: room(args.conversationId), messageId: id6(args.messageId, "messageId"), text: text4(args.text) } };
4706
+ }
4707
+ case "credential": {
4708
+ const args = record3(body.args, ["installationId", "generation", "credential"]);
4709
+ if (!Number.isSafeInteger(args.generation) || args.generation < 1) invalid11("generation");
4710
+ if (!isConnectorRelayCredential(args.credential)) invalid11("credential");
4711
+ return { ...head, op: "credential", args: {
4712
+ installationId: id6(args.installationId, "installationId", CONNECTOR_RELAY_INSTALLATION_PATTERN),
4713
+ generation: args.generation,
4714
+ credential: args.credential
4715
+ } };
4716
+ }
4717
+ default:
4718
+ return invalid11("op");
4719
+ }
4720
+ }
4721
+ __name(parseConnectorRelayRequest, "parseConnectorRelayRequest");
4722
+
3674
4723
  // ../backend-contracts/src/deliveryObservation.ts
3675
4724
  var isTerminalDeliveryOutcome = /* @__PURE__ */ __name((outcome) => !["unknown", "pending"].includes(outcome), "isTerminalDeliveryOutcome");
3676
4725
  function mergeDeliveryObservation(current, next, expected) {
3677
- if (next.schemaVersion !== 2 || !Number.isSafeInteger(next.revision) || next.revision < 0 || !["unknown", "pending", "published", "cancelled", "expired", "rejected"].includes(next.outcome) || Object.entries(expected).some(([key2, value]) => next[key2] !== value)) return current;
4726
+ if (next.schemaVersion !== 2 || !Number.isSafeInteger(next.revision) || next.revision < 0 || !["unknown", "pending", "published", "cancelled", "expired", "rejected"].includes(next.outcome) || Object.entries(expected).some(([key, value]) => next[key] !== value)) return current;
3678
4727
  if (current && (next.revision < current.revision || Object.keys(expected).length < 5 && (current.installationId !== next.installationId || current.environmentId !== next.environmentId) || isTerminalDeliveryOutcome(current.outcome) && next.outcome !== current.outcome || next.revision === current.revision && next.outcome !== current.outcome)) return current;
3679
4728
  return next;
3680
4729
  }
@@ -3695,7 +4744,7 @@ __name(classifyTransferHttpFailure, "classifyTransferHttpFailure");
3695
4744
  function classifyTransferReceipt(value, expected) {
3696
4745
  if (!value || typeof value !== "object" || Array.isArray(value)) return "invalid";
3697
4746
  const receipt = value;
3698
- if (Object.entries(expected).some(([key2, field]) => receipt[key2] !== field)) return "invalid";
4747
+ if (Object.entries(expected).some(([key, field]) => receipt[key] !== field)) return "invalid";
3699
4748
  switch (receipt.status) {
3700
4749
  case "succeeded":
3701
4750
  return "resultError" in receipt || !receipt.result || typeof receipt.result !== "object" || Array.isArray(receipt.result) ? "uncertain" : "result";
@@ -3712,17 +4761,8 @@ function classifyTransferReceipt(value, expected) {
3712
4761
  __name(classifyTransferReceipt, "classifyTransferReceipt");
3713
4762
 
3714
4763
  // ../backend-contracts/src/artifacts.ts
3715
- var ARTIFACT_PROTOCOL_VERSION = 2;
3716
- var ARTIFACT_PROTOCOL_MIN_VERSION = 2;
3717
- var artifactSchemaName = /* @__PURE__ */ __name((version) => `canon.artifact.v${version}`, "artifactSchemaName");
3718
4764
  var ARTIFACT_COMMAND_MAX_BYTES = 64 * 1024;
3719
4765
  var ARTIFACT_STATE_MAX_BYTES = 128 * 1024;
3720
- var ARTIFACT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,159}$/;
3721
- var ARTIFACT_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
3722
- var RESERVED_KEYS = /* @__PURE__ */ new Set(["constructor", "prototype", "toString", "__proto__", "hasOwnProperty", "valueOf"]);
3723
- var ARTIFACT_KINDS = ["chess", "form", "image"];
3724
- var ARTIFACT_COMMAND_TYPES = ["create", "chess.move", "chess.resign", "form.set", "form.fields", "image.add", "image.select", "archive"];
3725
- var ARTIFACT_FORM_FIELD_TYPES = ["text", "textarea", "number", "date", "select", "checkbox", "email", "tel", "url"];
3726
4766
  var ARTIFACT_LIMITS = Object.freeze({
3727
4767
  titleChars: 120,
3728
4768
  chessMaxPlies: 600,
@@ -3747,604 +4787,7 @@ var ARTIFACT_LIMITS = Object.freeze({
3747
4787
  outcomes: 200,
3748
4788
  outcomeMessageChars: 500
3749
4789
  });
3750
- function isArtifactId(value) {
3751
- return typeof value === "string" && ARTIFACT_ID_PATTERN.test(value);
3752
- }
3753
- __name(isArtifactId, "isArtifactId");
3754
- function isArtifactKey(value) {
3755
- return typeof value === "string" && ARTIFACT_KEY_PATTERN.test(value) && !RESERVED_KEYS.has(value);
3756
- }
3757
- __name(isArtifactKey, "isArtifactKey");
3758
- var ArtifactValidationError = class extends Error {
3759
- static {
3760
- __name(this, "ArtifactValidationError");
3761
- }
3762
- constructor(message) {
3763
- super(message);
3764
- this.name = "ArtifactValidationError";
3765
- }
3766
- };
3767
- var isObject = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isObject");
3768
- function quoteArtifactText(value) {
3769
- if (typeof value === "number" || typeof value === "boolean") return JSON.stringify(String(value));
3770
- if (typeof value !== "string") return value === null ? "(null)" : value === void 0 ? "(nothing)" : Array.isArray(value) ? "(a list)" : typeof value === "object" ? "(an object)" : "(an unsupported value)";
3771
- return JSON.stringify(value.length > 80 ? `${value.slice(0, 80)}\u2026` : value);
3772
- }
3773
- __name(quoteArtifactText, "quoteArtifactText");
3774
- var CONTROL_RUNS = /[\u0000-\u001F\u007F-\u009F\u2028\u2029]+/g;
3775
- function artifactSingleLine(value) {
3776
- return value.replace(CONTROL_RUNS, " ").trim();
3777
- }
3778
- __name(artifactSingleLine, "artifactSingleLine");
3779
- var fail = /* @__PURE__ */ __name((message) => {
3780
- throw new ArtifactValidationError(message);
3781
- }, "fail");
3782
- function exactKeys(value, allowed, where) {
3783
- for (const key2 of Object.keys(value)) if (!allowed.includes(key2)) fail(`Unexpected property ${quoteArtifactText(key2)} in ${where}`);
3784
- }
3785
- __name(exactKeys, "exactKeys");
3786
- function boundedText(value, maximum, what, options = {}) {
3787
- if (value === void 0 && !options.required) return void 0;
3788
- if (typeof value !== "string") return fail(`${what} must be text`);
3789
- const text3 = artifactSingleLine(value);
3790
- if (options.required && !text3) return fail(`${what} must not be empty`);
3791
- if (text3.length > maximum) return fail(`${what} must be at most ${maximum} characters`);
3792
- return text3 || void 0;
3793
- }
3794
- __name(boundedText, "boundedText");
3795
- var ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
3796
- function isCalendarDate(value) {
3797
- const match = ISO_DATE.exec(value);
3798
- if (!match) return false;
3799
- const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])];
3800
- if (month < 1 || month > 12 || day < 1) return false;
3801
- const days = [31, year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1];
3802
- return day <= days;
3803
- }
3804
- __name(isCalendarDate, "isCalendarDate");
3805
- function roundFormNumber(value, decimals) {
3806
- if (!Number.isFinite(value) || !Number.isSafeInteger(decimals) || decimals < 0 || decimals > 20) return value;
3807
- const [mantissa, exponent = "0"] = String(Math.abs(value)).split("e");
3808
- const shifted = Math.round(Number(`${mantissa}e${Number(exponent) + decimals}`));
3809
- const [m2, e2 = "0"] = String(shifted).split("e");
3810
- const rounded = Number(`${m2}e${Number(e2) - decimals}`);
3811
- if (!Number.isFinite(rounded)) return value;
3812
- const signed = value < 0 ? -rounded : rounded;
3813
- return signed === 0 ? 0 : signed;
3814
- }
3815
- __name(roundFormNumber, "roundFormNumber");
3816
4790
  var NUMBER_MAX_TEXT = String(ARTIFACT_LIMITS.formNumberMax).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
3817
- function validateFormValue(spec, value) {
3818
- const name = spec.label ? quoteArtifactText(spec.label) : "Value";
3819
- if (value === void 0 || value === null || value === "") return null;
3820
- switch (spec.type) {
3821
- case "text":
3822
- case "textarea":
3823
- case "email":
3824
- case "tel":
3825
- case "url":
3826
- if (typeof value !== "string") return fail(`${name} must be text`);
3827
- if (value.length > ARTIFACT_LIMITS.formValueChars) return fail(`${name} must be at most ${ARTIFACT_LIMITS.formValueChars} characters`);
3828
- return value;
3829
- case "date":
3830
- if (typeof value !== "string" || !isCalendarDate(value)) return fail(`${name} must be a calendar date (YYYY-MM-DD)`);
3831
- return value;
3832
- case "select":
3833
- if (typeof value !== "string" || !spec.options?.includes(value)) return fail(`${name} must be one of: ${(spec.options ?? []).slice(0, 10).map(quoteArtifactText).join(", ")}${(spec.options?.length ?? 0) > 10 ? ", \u2026" : ""}`);
3834
- return value;
3835
- case "number":
3836
- if (typeof value !== "number" || !Number.isFinite(value)) return fail(`${name} must be a number`);
3837
- if (Math.abs(value) > ARTIFACT_LIMITS.formNumberMax) return fail(`${name} must be between -${NUMBER_MAX_TEXT} and ${NUMBER_MAX_TEXT}`);
3838
- return spec.decimals === void 0 ? value === 0 ? 0 : value : roundFormNumber(value, spec.decimals);
3839
- case "checkbox":
3840
- if (typeof value !== "boolean") return fail(`${name} must be true or false`);
3841
- return value;
3842
- default:
3843
- return fail(`${name} has an unknown type`);
3844
- }
3845
- }
3846
- __name(validateFormValue, "validateFormValue");
3847
- function formValuesEqual(a, b) {
3848
- const left = a === void 0 || a === "" ? null : a;
3849
- const right = b === void 0 || b === "" ? null : b;
3850
- return left === right;
3851
- }
3852
- __name(formValuesEqual, "formValuesEqual");
3853
- function formatFormValue(value) {
3854
- if (value === void 0 || value === null || value === "") return "empty";
3855
- if (typeof value === "boolean") return value ? "checked" : "unchecked";
3856
- if (typeof value === "number") return String(value);
3857
- return quoteArtifactText(value);
3858
- }
3859
- __name(formatFormValue, "formatFormValue");
3860
- function normalizeOptions(value, type, where) {
3861
- if (type !== "select") {
3862
- if (value !== void 0) fail(`Only select inputs have options (${where})`);
3863
- return void 0;
3864
- }
3865
- if (!Array.isArray(value) || value.length < 1 || value.length > ARTIFACT_LIMITS.formOptions) return fail(`${where} needs 1 to ${ARTIFACT_LIMITS.formOptions} options`);
3866
- const options = value.map((option) => boundedText(option, ARTIFACT_LIMITS.formOptionChars, `An option of ${where}`, { required: true }));
3867
- if (new Set(options).size !== options.length) fail(`Options of ${where} must be unique`);
3868
- return options;
3869
- }
3870
- __name(normalizeOptions, "normalizeOptions");
3871
- function normalizeDecimals(value, type, where) {
3872
- if (value === void 0) return void 0;
3873
- if (type !== "number") return fail(`Only number inputs have decimals (${where})`);
3874
- if (!Number.isSafeInteger(value) || value < 0 || value > ARTIFACT_LIMITS.formMaxDecimals) return fail(`Decimals of ${where} must be a whole number from 0 to ${ARTIFACT_LIMITS.formMaxDecimals}`);
3875
- return value;
3876
- }
3877
- __name(normalizeDecimals, "normalizeDecimals");
3878
- function normalizeFormField(value) {
3879
- if (!isObject(value)) return fail("Each field must be an object");
3880
- if (!isArtifactKey(value.id)) return fail(`Field ID ${quoteArtifactText(value.id ?? "")} must be 1-64 letters, digits, '-' or '_'`);
3881
- const where = `field ${quoteArtifactText(value.id)}`;
3882
- exactKeys(value, ["id", "label", "type", "options", "required", "placeholder", "help", "decimals"], where);
3883
- const label = boundedText(value.label, ARTIFACT_LIMITS.formLabelChars, `The label of ${where}`, { required: true });
3884
- if (typeof value.type !== "string" || !ARTIFACT_FORM_FIELD_TYPES.includes(value.type)) return fail(`The type of ${where} must be one of ${ARTIFACT_FORM_FIELD_TYPES.join(", ")}`);
3885
- const type = value.type;
3886
- if (value.required !== void 0 && typeof value.required !== "boolean") fail(`required of ${where} must be true or false`);
3887
- const options = normalizeOptions(value.options, type, where);
3888
- const decimals = normalizeDecimals(value.decimals, type, where);
3889
- const placeholder = boundedText(value.placeholder, ARTIFACT_LIMITS.formHintChars, `The placeholder of ${where}`);
3890
- const help = boundedText(value.help, ARTIFACT_LIMITS.formHintChars, `The help text of ${where}`);
3891
- return {
3892
- id: value.id,
3893
- label,
3894
- type,
3895
- ...options ? { options } : {},
3896
- ...value.required === true ? { required: true } : {},
3897
- ...placeholder ? { placeholder } : {},
3898
- ...help ? { help } : {},
3899
- ...decimals !== void 0 ? { decimals } : {}
3900
- };
3901
- }
3902
- __name(normalizeFormField, "normalizeFormField");
3903
- function normalizeColumn(value) {
3904
- if (!isObject(value)) return fail("Each table column must be an object");
3905
- if (!isArtifactKey(value.id)) return fail(`Column ID ${quoteArtifactText(value.id ?? "")} must be 1-64 letters, digits, '-' or '_'`);
3906
- const where = `column ${quoteArtifactText(value.id)}`;
3907
- exactKeys(value, ["id", "label", "type", "options", "decimals", "sum"], where);
3908
- const label = boundedText(value.label, ARTIFACT_LIMITS.formLabelChars, `The label of ${where}`, { required: true });
3909
- if (typeof value.type !== "string" || value.type === "textarea" || !ARTIFACT_FORM_FIELD_TYPES.includes(value.type)) return fail(`The type of ${where} must be one of ${ARTIFACT_FORM_FIELD_TYPES.filter((type2) => type2 !== "textarea").join(", ")}`);
3910
- const type = value.type;
3911
- const options = normalizeOptions(value.options, type, where);
3912
- const decimals = normalizeDecimals(value.decimals, type, where);
3913
- if (value.sum !== void 0 && typeof value.sum !== "boolean") fail(`sum of ${where} must be true or false`);
3914
- if (value.sum === true && type !== "number") fail(`Only number columns can be summed (${where})`);
3915
- return { id: value.id, label, type, ...options ? { options } : {}, ...decimals !== void 0 ? { decimals } : {}, ...value.sum === true ? { sum: true } : {} };
3916
- }
3917
- __name(normalizeColumn, "normalizeColumn");
3918
- function normalizeFormTable(value) {
3919
- if (!isObject(value)) return fail("table must be { label?, columns }");
3920
- exactKeys(value, ["label", "columns"], "the table");
3921
- const label = boundedText(value.label, ARTIFACT_LIMITS.formLabelChars, "The table label");
3922
- if (!Array.isArray(value.columns) || value.columns.length < 1 || value.columns.length > ARTIFACT_LIMITS.formColumns) return fail(`A table needs 1 to ${ARTIFACT_LIMITS.formColumns} columns`);
3923
- const columns = value.columns.map(normalizeColumn);
3924
- if (new Set(columns.map((column) => column.id)).size !== columns.length) fail("Column IDs must be unique");
3925
- return { ...label ? { label } : {}, columns };
3926
- }
3927
- __name(normalizeFormTable, "normalizeFormTable");
3928
- function normalizeFormCells(table, value, where) {
3929
- if (!isObject(value)) return fail(`The cells of ${where} must be an object`);
3930
- const columns = new Map(table.columns.map((column) => [column.id, column]));
3931
- for (const key2 of Object.keys(value)) if (!columns.has(key2)) fail(`Unknown column ${quoteArtifactText(key2)} in ${where}. Columns: ${table.columns.map((column) => column.id).join(", ")}`);
3932
- const cells = {};
3933
- for (const column of table.columns) cells[column.id] = validateFormValue(column, Object.hasOwn(value, column.id) ? value[column.id] : null);
3934
- return cells;
3935
- }
3936
- __name(normalizeFormCells, "normalizeFormCells");
3937
- function normalizeFormInput(input) {
3938
- if (!isObject(input)) return fail("A form needs { fields, values?, table?, rows? }");
3939
- exactKeys(input, ["fields", "values", "table", "rows"], "the form");
3940
- if (!Array.isArray(input.fields) || input.fields.length > ARTIFACT_LIMITS.formFields) return fail(`A form needs a fields list of at most ${ARTIFACT_LIMITS.formFields} fields`);
3941
- const fields = input.fields.map(normalizeFormField);
3942
- const ids = /* @__PURE__ */ new Set();
3943
- for (const field of fields) {
3944
- if (ids.has(field.id)) fail(`Field ID ${quoteArtifactText(field.id)} is used twice`);
3945
- ids.add(field.id);
3946
- }
3947
- const values = {};
3948
- if (input.values !== void 0 && !isObject(input.values)) fail("values must be an object keyed by field ID");
3949
- const given = input.values ?? {};
3950
- for (const key2 of Object.keys(given)) if (!ids.has(key2)) fail(`Unknown field ${quoteArtifactText(key2)} in values. Fields: ${fields.map((field) => field.id).join(", ") || "none"}`);
3951
- for (const field of fields) values[field.id] = validateFormValue(field, Object.hasOwn(given, field.id) ? given[field.id] : null);
3952
- const table = input.table === void 0 ? void 0 : normalizeFormTable(input.table);
3953
- const rows = [];
3954
- if (input.rows !== void 0) {
3955
- if (!Array.isArray(input.rows)) return fail("rows must be a list");
3956
- if (input.rows.length && !table) fail("Rows need a table with columns");
3957
- if (input.rows.length > ARTIFACT_LIMITS.formRows) fail(`A table holds at most ${ARTIFACT_LIMITS.formRows} rows`);
3958
- const rowIds = /* @__PURE__ */ new Set();
3959
- input.rows.forEach((row, index) => {
3960
- if (!isObject(row)) fail(`Row ${index + 1} must be { id?, cells }`);
3961
- const value = row;
3962
- exactKeys(value, ["id", "cells"], `row ${index + 1}`);
3963
- const id6 = value.id === void 0 ? `r-${index + 1}` : value.id;
3964
- if (!isArtifactKey(id6)) fail(`Row ID ${quoteArtifactText(id6)} must be 1-64 letters, digits, '-' or '_'`);
3965
- if (rowIds.has(id6)) fail(`Row ID ${quoteArtifactText(id6)} is used twice`);
3966
- rowIds.add(id6);
3967
- rows.push({ id: id6, cells: normalizeFormCells(table, value.cells ?? {}, `row ${index + 1}`) });
3968
- });
3969
- }
3970
- return { fields, values, ...table ? { table } : {}, rows };
3971
- }
3972
- __name(normalizeFormInput, "normalizeFormInput");
3973
-
3974
- // ../backend-contracts/src/artifactActions.ts
3975
- var ARTIFACT_UPDATE_ACTION_TYPES = ["chess.move", "chess.resign", "form.set", "form.fields", "image.select", "archive"];
3976
- function object(properties, required = [], description) {
3977
- return { type: "object", properties, required, additionalProperties: false, ...description ? { description } : {} };
3978
- }
3979
- __name(object, "object");
3980
- function id5(description) {
3981
- return { type: "string", pattern: ARTIFACT_ID_PATTERN.source, description };
3982
- }
3983
- __name(id5, "id");
3984
- function key(description) {
3985
- return { type: "string", pattern: ARTIFACT_KEY_PATTERN.source, description };
3986
- }
3987
- __name(key, "key");
3988
- function scalarSchema() {
3989
- return { type: ["string", "number", "boolean", "null"] };
3990
- }
3991
- __name(scalarSchema, "scalarSchema");
3992
- function valueMap(description) {
3993
- return { type: "object", additionalProperties: scalarSchema(), description };
3994
- }
3995
- __name(valueMap, "valueMap");
3996
- function text2(max, description) {
3997
- return { type: "string", minLength: 1, maxLength: max, ...description ? { description } : {} };
3998
- }
3999
- __name(text2, "text");
4000
- function fieldSchemas() {
4001
- const options = { type: "array", items: text2(ARTIFACT_LIMITS.formOptionChars), minItems: 1, maxItems: ARTIFACT_LIMITS.formOptions, description: "The choices (select only)." };
4002
- const decimals = { type: "integer", minimum: 0, maximum: ARTIFACT_LIMITS.formMaxDecimals, description: "Number only: round to this many decimals." };
4003
- return {
4004
- field: object({
4005
- id: key("Stable field ID: letters, digits, - or _."),
4006
- label: text2(ARTIFACT_LIMITS.formLabelChars),
4007
- type: { enum: [...ARTIFACT_FORM_FIELD_TYPES] },
4008
- options,
4009
- required: { type: "boolean", description: "Marked as required (a hint; empty values are allowed)." },
4010
- placeholder: text2(ARTIFACT_LIMITS.formHintChars),
4011
- help: text2(ARTIFACT_LIMITS.formHintChars),
4012
- decimals
4013
- }, ["id", "label", "type"]),
4014
- column: object({
4015
- id: key("Stable column ID."),
4016
- label: text2(ARTIFACT_LIMITS.formLabelChars),
4017
- type: { enum: ARTIFACT_FORM_FIELD_TYPES.filter((type) => type !== "textarea") },
4018
- options,
4019
- decimals,
4020
- sum: { type: "boolean", description: "Number only: show the column total." }
4021
- }, ["id", "label", "type"])
4022
- };
4023
- }
4024
- __name(fieldSchemas, "fieldSchemas");
4025
- var ARTIFACT_ID_DESCRIPTION = "The work\u2019s artifactId (from artifact_list, artifact_create or a message reference).";
4026
- var LAST_ATTACHMENT_INDEX = VERB_LIMITS.messageAttachments - 1;
4027
- function artifactActionSchemas() {
4028
- const { field, column } = fieldSchemas();
4029
- const fraction = /* @__PURE__ */ __name(() => ({ type: "number", minimum: 0, maximum: 1 }), "fraction");
4030
- return {
4031
- create: object({
4032
- kind: { enum: ["chess", "form", "image"] },
4033
- title: text2(ARTIFACT_LIMITS.titleChars),
4034
- chess: object({ playAs: { enum: ["white", "black"], description: "Your seat. Omit for an open board." }, fen: text2(100, "Optional starting position (FEN).") }, [], 'Only for kind "chess".'),
4035
- form: object({
4036
- fields: { type: "array", maxItems: ARTIFACT_LIMITS.formFields, items: field },
4037
- values: valueMap("Initial values keyed by field ID."),
4038
- table: object({ label: text2(ARTIFACT_LIMITS.formLabelChars), columns: { type: "array", minItems: 1, maxItems: ARTIFACT_LIMITS.formColumns, items: column } }, ["columns"], "Optional table of line items."),
4039
- rows: { type: "array", maxItems: ARTIFACT_LIMITS.formRows, items: object({ id: key("Optional row ID."), cells: valueMap("Cell values keyed by column ID.") }, ["cells"]) }
4040
- }, ["fields"], 'Required for kind "form".')
4041
- }, ["kind", "title"]),
4042
- update: {
4043
- description: "What to change. Pick one action by its type.",
4044
- oneOf: [
4045
- object({ type: { const: "chess.move" }, move: text2(16, 'Your move in SAN ("Nf3", "exd5", "O-O", "e8=Q") or UCI ("g1f3").') }, ["type", "move"]),
4046
- object({ type: { const: "chess.resign" } }, ["type"]),
4047
- object({
4048
- type: { const: "form.set" },
4049
- values: valueMap('Field values keyed by field ID. Numbers may be given as numeric text; "" or null empties a value.'),
4050
- cells: { type: "array", maxItems: ARTIFACT_LIMITS.formChanges, items: object({ row: key("Row ID"), column: key("Column ID"), value: scalarSchema() }, ["row", "column", "value"]) },
4051
- addRows: { type: "array", maxItems: ARTIFACT_LIMITS.formChanges, items: object({ id: key("Optional row ID; generated when omitted (returned as addedRowIds)."), cells: valueMap("Cell values keyed by column ID.") }, ["cells"]) },
4052
- removeRows: { type: "array", maxItems: ARTIFACT_LIMITS.formChanges, items: key("Row ID") }
4053
- }, ["type"]),
4054
- object({ type: { const: "form.fields" }, add: { type: "array", maxItems: ARTIFACT_LIMITS.formFields, items: field }, remove: { type: "array", maxItems: ARTIFACT_LIMITS.formFields, items: key("Field ID") } }, ["type"]),
4055
- object({ type: { const: "image.select" }, variantId: id5("The version to make current.") }, ["type", "variantId"]),
4056
- object({ type: { const: "archive" }, archived: { type: "boolean", description: "true archives the work (read-only); false restores it." } }, ["type", "archived"])
4057
- ]
4058
- },
4059
- generateImage: object({
4060
- prompt: text2(ARTIFACT_LIMITS.imagePromptChars, "What to generate or change."),
4061
- label: text2(ARTIFACT_LIMITS.imageLabelChars, 'A short name for the new version, e.g. "darker sky".'),
4062
- from: {
4063
- description: '"current", "new", or the version to edit (a version ID, or { variantId }).',
4064
- anyOf: [{ type: "string", pattern: ARTIFACT_ID_PATTERN.source }, object({ variantId: id5("The version to edit.") }, ["variantId"])]
4065
- },
4066
- region: object({ x: fraction(), y: fraction(), width: fraction(), height: fraction() }, ["x", "y", "width", "height"], "Optional area to change.")
4067
- }, ["prompt", "label", "from"]),
4068
- addImage: object({
4069
- label: text2(ARTIFACT_LIMITS.imageLabelChars, "A short name for the version."),
4070
- prompt: text2(ARTIFACT_LIMITS.imagePromptChars, "Optional: how the image was made."),
4071
- sourceVariantId: id5("Optional: the version this one was derived from."),
4072
- path: text2(4096, "Absolute path of a local JPEG or PNG file (only where the host allows local files)."),
4073
- messageId: id5("A message in this conversation with an image attached."),
4074
- attachmentIndex: { type: "integer", minimum: 0, maximum: LAST_ATTACHMENT_INDEX, description: "Which attachment of that message (default: its first image)." }
4075
- }, ["label"])
4076
- };
4077
- }
4078
- __name(artifactActionSchemas, "artifactActionSchemas");
4079
- function withArtifactId(schema) {
4080
- return { ...schema, properties: { artifactId: id5(ARTIFACT_ID_DESCRIPTION), ...schema.properties }, required: ["artifactId", ...schema.required] };
4081
- }
4082
- __name(withArtifactId, "withArtifactId");
4083
- function artifactToolInputSchemas() {
4084
- const actions = artifactActionSchemas();
4085
- return {
4086
- artifact_list: object({}),
4087
- artifact_read: object({
4088
- artifactId: id5(ARTIFACT_ID_DESCRIPTION),
4089
- revisionId: id5("Optional earlier revision to read (from a message reference)."),
4090
- variantId: id5("Image work: show this version instead of the current one.")
4091
- }, ["artifactId"]),
4092
- artifact_create: actions.create,
4093
- artifact_update: object({
4094
- artifactId: id5(ARTIFACT_ID_DESCRIPTION),
4095
- action: actions.update,
4096
- basedOnRevisionId: id5("Rarely needed: base the change on this revision instead of the version you last saw.")
4097
- }, ["artifactId", "action"]),
4098
- artifact_generate_image: withArtifactId(actions.generateImage),
4099
- artifact_add_image: withArtifactId(actions.addImage)
4100
- };
4101
- }
4102
- __name(artifactToolInputSchemas, "artifactToolInputSchemas");
4103
- var isObject2 = /* @__PURE__ */ __name((input) => input !== null && typeof input === "object" && !Array.isArray(input), "isObject");
4104
- var fail2 = /* @__PURE__ */ __name((message) => {
4105
- throw new ArtifactValidationError(message);
4106
- }, "fail");
4107
- var quote = quoteArtifactText;
4108
- function exactKeys2(input, allowed, where) {
4109
- for (const name of Object.keys(input)) if (!allowed.includes(name)) fail2(`Unexpected ${JSON.stringify(name.slice(0, 40))} in ${where}`);
4110
- }
4111
- __name(exactKeys2, "exactKeys");
4112
- function textArg(input, name, max, required = false) {
4113
- if (input === void 0 && !required) return void 0;
4114
- if (typeof input !== "string" || !input.trim() || input.length > max) return fail2(`${name} must be text of at most ${max} characters`);
4115
- return input;
4116
- }
4117
- __name(textArg, "textArg");
4118
- function lineArg(input, name, max) {
4119
- const line = artifactSingleLine(textArg(input, name, max, true));
4120
- return line || fail2(`${name} must be text of at most ${max} characters`);
4121
- }
4122
- __name(lineArg, "lineArg");
4123
- function idArg(input, name) {
4124
- if (input === void 0) return void 0;
4125
- return isArtifactId(input) ? input : fail2(`${name} must be an ID (letters, digits, _ . : -)`);
4126
- }
4127
- __name(idArg, "idArg");
4128
- var isScalar = /* @__PURE__ */ __name((input) => input === null || typeof input === "string" || typeof input === "boolean" || typeof input === "number" && Number.isFinite(input), "isScalar");
4129
- function scalar(input, where) {
4130
- return isScalar(input) ? input : fail2(`${where} must be text, a number, true, false or null`);
4131
- }
4132
- __name(scalar, "scalar");
4133
- function scalars(input, what, known) {
4134
- return Object.fromEntries(Object.entries(input).map(([name, item]) => {
4135
- if (known && !known.ids.includes(name)) fail2(`Unknown ${what} ${quote(name)} in ${known.where}. ${known.list}: ${known.ids.join(", ") || "none"}`);
4136
- return [name, scalar(item, `The value of ${what} ${quote(name)}`)];
4137
- }));
4138
- }
4139
- __name(scalars, "scalars");
4140
- function uniqueFields(fields) {
4141
- const seen = /* @__PURE__ */ new Set();
4142
- for (const field of fields) {
4143
- if (seen.has(field.id)) fail2(`Field ID ${quote(field.id)} is used twice`);
4144
- seen.add(field.id);
4145
- }
4146
- }
4147
- __name(uniqueFields, "uniqueFields");
4148
- function chessAction(title, input, prefix) {
4149
- if (input.playAs !== void 0 && input.playAs !== "white" && input.playAs !== "black") fail2(`${prefix}playAs must be "white" or "black"`);
4150
- if (input.fen !== void 0 && (typeof input.fen !== "string" || !input.fen.trim() || input.fen.length > 100)) fail2(`${prefix}fen must be a FEN string`);
4151
- if (input.opponent !== void 0 && !isArtifactId(input.opponent)) fail2("opponent must be a participant ID");
4152
- return {
4153
- kind: "chess",
4154
- title,
4155
- ...input.playAs !== void 0 ? { playAs: input.playAs } : {},
4156
- ...input.opponent !== void 0 ? { opponent: input.opponent } : {},
4157
- ...input.fen !== void 0 ? { fen: input.fen.trim() } : {}
4158
- };
4159
- }
4160
- __name(chessAction, "chessAction");
4161
- function formAction(title, input) {
4162
- if (!Array.isArray(input.fields) || input.fields.length > ARTIFACT_LIMITS.formFields) return fail2(`A form needs a fields list of at most ${ARTIFACT_LIMITS.formFields} fields`);
4163
- const fields = input.fields.map(normalizeFormField);
4164
- uniqueFields(fields);
4165
- const fieldIds = fields.map((field) => field.id);
4166
- if (input.values !== void 0 && !isObject2(input.values)) fail2("values must be an object keyed by field ID");
4167
- const values = input.values === void 0 ? void 0 : scalars(input.values, "field", { ids: fieldIds, where: "values", list: "Fields" });
4168
- const table = input.table === void 0 ? void 0 : normalizeFormTable(input.table);
4169
- let rows;
4170
- if (input.rows !== void 0) {
4171
- if (!Array.isArray(input.rows)) return fail2("rows must be a list");
4172
- if (input.rows.length && !table) fail2("Rows need a table with columns");
4173
- if (input.rows.length > ARTIFACT_LIMITS.formRows) fail2(`A table holds at most ${ARTIFACT_LIMITS.formRows} rows`);
4174
- const columnIds = table?.columns.map((column) => column.id) ?? [];
4175
- const rowIds = /* @__PURE__ */ new Set();
4176
- rows = input.rows.map((row, index) => {
4177
- const where = `row ${index + 1}`;
4178
- if (!isObject2(row)) return fail2(`Row ${index + 1} must be { id?, cells }`);
4179
- exactKeys2(row, ["id", "cells"], where);
4180
- if (row.id !== void 0) {
4181
- if (!isArtifactKey(row.id)) fail2(`Row ID ${quote(row.id)} must be 1-64 letters, digits, '-' or '_'`);
4182
- if (rowIds.has(row.id)) fail2(`Row ID ${quote(row.id)} is used twice`);
4183
- rowIds.add(row.id);
4184
- }
4185
- if (row.cells !== void 0 && !isObject2(row.cells)) fail2(`The cells of ${where} must be an object`);
4186
- return { ...row.id !== void 0 ? { id: row.id } : {}, cells: scalars(row.cells ?? {}, "column", { ids: columnIds, where, list: "Columns" }) };
4187
- });
4188
- }
4189
- return { kind: "form", title, fields, ...values ? { values } : {}, ...table ? { table } : {}, ...rows ? { rows } : {} };
4190
- }
4191
- __name(formAction, "formAction");
4192
- function parseArtifactCreateAction(input) {
4193
- if (!isObject2(input)) return fail2("Describe the work to create: { kind, title, ... }");
4194
- const title = lineArg(input.title, "title", ARTIFACT_LIMITS.titleChars);
4195
- switch (input.kind) {
4196
- case "chess":
4197
- exactKeys2(input, ["kind", "title", "playAs", "opponent", "fen"], "a chess game");
4198
- return chessAction(title, input, "");
4199
- case "form":
4200
- exactKeys2(input, ["kind", "title", "fields", "values", "table", "rows"], "a form");
4201
- return formAction(title, input);
4202
- case "image":
4203
- exactKeys2(input, ["kind", "title"], "an image");
4204
- return { kind: "image", title };
4205
- default:
4206
- return fail2('kind must be "chess", "form" or "image"');
4207
- }
4208
- }
4209
- __name(parseArtifactCreateAction, "parseArtifactCreateAction");
4210
- function formSetAction(input) {
4211
- exactKeys2(input, ["type", "values", "cells", "addRows", "removeRows"], "form.set");
4212
- const action = { type: "form.set" };
4213
- let count = 0;
4214
- if (input.values !== void 0) {
4215
- if (!isObject2(input.values)) fail2("values must be an object keyed by field ID");
4216
- action.values = scalars(input.values, "field");
4217
- count += Object.keys(action.values).length;
4218
- }
4219
- if (input.cells !== void 0) {
4220
- if (!Array.isArray(input.cells)) fail2("cells must be a list of { row, column, value }");
4221
- action.cells = input.cells.map((cell) => {
4222
- if (!isObject2(cell) || typeof cell.row !== "string" || typeof cell.column !== "string" || !Object.hasOwn(cell, "value")) return fail2("Each cell must be { row, column, value }");
4223
- exactKeys2(cell, ["row", "column", "value"], "a cell");
4224
- return { row: cell.row, column: cell.column, value: scalar(cell.value, `The value of column ${quote(cell.column)} in row ${quote(cell.row)}`) };
4225
- });
4226
- count += action.cells.length;
4227
- }
4228
- if (input.addRows !== void 0) {
4229
- if (!Array.isArray(input.addRows)) fail2("addRows must be a list of { id?, cells }");
4230
- const taken = /* @__PURE__ */ new Set();
4231
- action.addRows = input.addRows.map((row) => {
4232
- if (!isObject2(row) || row.cells !== void 0 && !isObject2(row.cells)) return fail2("Each added row must be { id?, cells }");
4233
- exactKeys2(row, ["id", "cells"], "an added row");
4234
- if (row.id !== void 0) {
4235
- if (!isArtifactKey(row.id)) fail2(`Row ID ${quote(row.id)} must be 1-64 letters, digits, '-' or '_'`);
4236
- if (taken.has(row.id)) fail2(`Row ID ${quote(row.id)} is already used`);
4237
- taken.add(row.id);
4238
- }
4239
- return { ...row.id !== void 0 ? { id: row.id } : {}, cells: scalars(row.cells ?? {}, "column") };
4240
- });
4241
- count += action.addRows.length;
4242
- }
4243
- if (input.removeRows !== void 0) {
4244
- if (!Array.isArray(input.removeRows) || input.removeRows.some((item) => typeof item !== "string")) fail2("removeRows must be a list of row IDs");
4245
- action.removeRows = [...input.removeRows];
4246
- count += action.removeRows.length;
4247
- }
4248
- if (!count) fail2("form.set needs values, cells, addRows or removeRows");
4249
- if (count > ARTIFACT_LIMITS.formChanges) fail2(`One form.set can make at most ${ARTIFACT_LIMITS.formChanges} changes`);
4250
- return action;
4251
- }
4252
- __name(formSetAction, "formSetAction");
4253
- function formFieldsAction(input) {
4254
- exactKeys2(input, ["type", "add", "remove"], "form.fields");
4255
- if (input.add !== void 0 && !Array.isArray(input.add)) fail2("add must be a list of fields");
4256
- if (input.remove !== void 0 && (!Array.isArray(input.remove) || input.remove.some((item) => typeof item !== "string"))) fail2("remove must be a list of field IDs");
4257
- const add = input.add ?? [];
4258
- const remove = input.remove ?? [];
4259
- if (!add.length && !remove.length) fail2("form.fields needs fields to add or field IDs to remove");
4260
- if (add.length > ARTIFACT_LIMITS.formFields) fail2(`A form holds at most ${ARTIFACT_LIMITS.formFields} fields`);
4261
- const fields = add.map(normalizeFormField);
4262
- uniqueFields(fields);
4263
- const removed = /* @__PURE__ */ new Set();
4264
- for (const name of remove) {
4265
- if (removed.has(name)) fail2(`Field ${quote(name)} is removed twice`);
4266
- removed.add(name);
4267
- }
4268
- for (const field of fields) if (removed.has(field.id)) fail2(`Field ${quote(field.id)} cannot be removed and added again in one command; field types do not change`);
4269
- return { type: "form.fields", ...fields.length ? { add: fields } : {}, ...remove.length ? { remove: [...remove] } : {} };
4270
- }
4271
- __name(formFieldsAction, "formFieldsAction");
4272
- function parseArtifactUpdateAction(input) {
4273
- if (!isObject2(input) || typeof input.type !== "string" || !ARTIFACT_UPDATE_ACTION_TYPES.includes(input.type)) {
4274
- return fail2(`action.type must be one of ${ARTIFACT_UPDATE_ACTION_TYPES.join(", ")}`);
4275
- }
4276
- const type = input.type;
4277
- switch (type) {
4278
- case "chess.move": {
4279
- exactKeys2(input, ["type", "move"], "chess.move");
4280
- const move = typeof input.move === "string" ? input.move.trim() : "";
4281
- if (!move || move.length > 16) return fail2('move must be a move in SAN (for example "Nf3") or UCI (for example "g1f3")');
4282
- return { type, move };
4283
- }
4284
- case "chess.resign":
4285
- exactKeys2(input, ["type"], "chess.resign");
4286
- return { type };
4287
- case "image.select":
4288
- exactKeys2(input, ["type", "variantId"], "image.select");
4289
- if (!isArtifactId(input.variantId)) return fail2("variantId must be a version ID from the image work");
4290
- return { type, variantId: input.variantId };
4291
- case "archive":
4292
- exactKeys2(input, ["type", "archived"], "archive");
4293
- if (typeof input.archived !== "boolean") return fail2("archived must be true or false");
4294
- return { type, archived: input.archived };
4295
- case "form.fields":
4296
- return formFieldsAction(input);
4297
- case "form.set":
4298
- return formSetAction(input);
4299
- }
4300
- }
4301
- __name(parseArtifactUpdateAction, "parseArtifactUpdateAction");
4302
- var REGION_MESSAGE = "The region must be fractions of the image: x, y, width and height between 0 and 1";
4303
- function parseArtifactImageRegion(input) {
4304
- if (!isObject2(input)) return fail2(REGION_MESSAGE);
4305
- exactKeys2(input, ["x", "y", "width", "height"], "region");
4306
- const { x, y, width, height } = input;
4307
- if ([x, y, width, height].some((item) => typeof item !== "number" || !Number.isFinite(item) || item < 0 || item > 1) || width <= 0 || height <= 0 || x + width > 1 || y + height > 1) return fail2(REGION_MESSAGE);
4308
- return { x, y, width, height };
4309
- }
4310
- __name(parseArtifactImageRegion, "parseArtifactImageRegion");
4311
- function parseArtifactImageSource(input) {
4312
- if (input === "current" || input === "new") return input;
4313
- if (isArtifactId(input)) return { variantId: input };
4314
- if (isObject2(input) && Object.keys(input).length === 1 && isArtifactId(input.variantId)) return { variantId: input.variantId };
4315
- return fail2("from must be 'current', 'new' or a version ID");
4316
- }
4317
- __name(parseArtifactImageSource, "parseArtifactImageSource");
4318
- function parseArtifactGenerateImageAction(input) {
4319
- if (!isObject2(input)) return fail2("Describe the image to generate");
4320
- exactKeys2(input, ["prompt", "label", "from", "region"], "the image request");
4321
- const prompt = textArg(input.prompt, "prompt", ARTIFACT_LIMITS.imagePromptChars, true).trim();
4322
- const label = lineArg(input.label, "label", ARTIFACT_LIMITS.imageLabelChars);
4323
- const from = parseArtifactImageSource(input.from);
4324
- return { prompt, label, from, ...input.region !== void 0 ? { region: parseArtifactImageRegion(input.region) } : {} };
4325
- }
4326
- __name(parseArtifactGenerateImageAction, "parseArtifactGenerateImageAction");
4327
- function parseArtifactAddImageAction(input) {
4328
- if (!isObject2(input)) return fail2("Describe the image to add: { label, path | messageId }");
4329
- exactKeys2(input, ["label", "prompt", "sourceVariantId", "path", "messageId", "attachmentIndex"], "the image");
4330
- const label = lineArg(input.label, "label", ARTIFACT_LIMITS.imageLabelChars);
4331
- const prompt = textArg(input.prompt, "prompt", ARTIFACT_LIMITS.imagePromptChars)?.trim();
4332
- const sourceVariantId = idArg(input.sourceVariantId, "sourceVariantId");
4333
- const path = textArg(input.path, "path", 4096);
4334
- const messageId2 = idArg(input.messageId, "messageId");
4335
- const index = input.attachmentIndex;
4336
- if (index !== void 0 && (!Number.isSafeInteger(index) || index < 0 || index > LAST_ATTACHMENT_INDEX)) fail2(`attachmentIndex must be from 0 to ${LAST_ATTACHMENT_INDEX}`);
4337
- if (path && (messageId2 || index !== void 0)) fail2("Give either path or messageId (with attachmentIndex), not both");
4338
- return {
4339
- label,
4340
- ...prompt ? { prompt } : {},
4341
- ...sourceVariantId ? { sourceVariantId } : {},
4342
- ...path ? { path } : {},
4343
- ...messageId2 ? { messageId: messageId2 } : {},
4344
- ...index !== void 0 ? { attachmentIndex: index } : {}
4345
- };
4346
- }
4347
- __name(parseArtifactAddImageAction, "parseArtifactAddImageAction");
4348
4791
 
4349
4792
  // ../backend-contracts/src/mlsDevCredentialReconciliation.ts
4350
4793
  var MLS_DEV_CREDENTIAL_RECONCILIATION_CHALLENGE_TTL_MS = 3e5;
@@ -4359,32 +4802,32 @@ var MlsDevCredentialReconciliationValidationError = class extends Error {
4359
4802
  this.name = "MlsDevCredentialReconciliationValidationError";
4360
4803
  }
4361
4804
  };
4362
- var utf85 = new TextEncoder();
4363
- var domain2 = utf85.encode("canon.mls.credential-reconciliation-proof.v1\0");
4364
- function invalid9() {
4805
+ var utf86 = new TextEncoder();
4806
+ var domain2 = utf86.encode("canon.mls.credential-reconciliation-proof.v1\0");
4807
+ function invalid12() {
4365
4808
  throw new MlsDevCredentialReconciliationValidationError();
4366
4809
  }
4367
- __name(invalid9, "invalid");
4368
- function boundary7(read) {
4810
+ __name(invalid12, "invalid");
4811
+ function boundary9(read) {
4369
4812
  try {
4370
4813
  return read();
4371
4814
  } catch {
4372
- return invalid9();
4815
+ return invalid12();
4373
4816
  }
4374
4817
  }
4375
- __name(boundary7, "boundary");
4818
+ __name(boundary9, "boundary");
4376
4819
  function bounded7(value) {
4377
- if (utf85.encode(JSON.stringify(value)).length > MLS_DEV_CREDENTIAL_RECONCILIATION_MAX_BYTES) invalid9();
4820
+ if (utf86.encode(JSON.stringify(value)).length > MLS_DEV_CREDENTIAL_RECONCILIATION_MAX_BYTES) invalid12();
4378
4821
  return Object.freeze(value);
4379
4822
  }
4380
4823
  __name(bounded7, "bounded");
4381
- function encoded5(value, bytes) {
4824
+ function encoded6(value, bytes) {
4382
4825
  decodeCanonicalMlsBase64Url(value, bytes);
4383
4826
  return value;
4384
4827
  }
4385
- __name(encoded5, "encoded");
4828
+ __name(encoded6, "encoded");
4386
4829
  function parseMlsDevCredentialReconciliationBegin(value) {
4387
- return boundary7(() => {
4830
+ return boundary9(() => {
4388
4831
  const input = readMlsDataRecord(value, ["version", "deviceId", "requestId", "expectedCredentialGeneration"]);
4389
4832
  return bounded7({
4390
4833
  version: requireMlsLiteral(input.version, 1),
@@ -4396,7 +4839,7 @@ function parseMlsDevCredentialReconciliationBegin(value) {
4396
4839
  }
4397
4840
  __name(parseMlsDevCredentialReconciliationBegin, "parseMlsDevCredentialReconciliationBegin");
4398
4841
  function parseMlsDevCredentialReconciliationChallenge(value) {
4399
- return boundary7(() => {
4842
+ return boundary9(() => {
4400
4843
  const input = readMlsDataRecord(value, [
4401
4844
  "version",
4402
4845
  "challengeId",
@@ -4409,12 +4852,12 @@ function parseMlsDevCredentialReconciliationChallenge(value) {
4409
4852
  ]);
4410
4853
  const device = parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: input.device }).device;
4411
4854
  const issuedAtMs = requireMlsInteger(input.issuedAtMs), expiresAtMs = requireMlsInteger(input.expiresAtMs);
4412
- if (issuedAtMs < device.registeredAtMs || expiresAtMs - issuedAtMs !== MLS_DEV_CREDENTIAL_RECONCILIATION_CHALLENGE_TTL_MS) invalid9();
4855
+ if (issuedAtMs < device.registeredAtMs || expiresAtMs - issuedAtMs !== MLS_DEV_CREDENTIAL_RECONCILIATION_CHALLENGE_TTL_MS) invalid12();
4413
4856
  return bounded7({
4414
4857
  version: requireMlsLiteral(input.version, 1),
4415
4858
  challengeId: requireMlsUuid(input.challengeId),
4416
4859
  requestId: requireMlsUuid(input.requestId),
4417
- nonce: encoded5(input.nonce, 32),
4860
+ nonce: encoded6(input.nonce, 32),
4418
4861
  device,
4419
4862
  expectedCredentialGeneration: requireMlsInteger(input.expectedCredentialGeneration),
4420
4863
  issuedAtMs,
@@ -4424,18 +4867,18 @@ function parseMlsDevCredentialReconciliationChallenge(value) {
4424
4867
  }
4425
4868
  __name(parseMlsDevCredentialReconciliationChallenge, "parseMlsDevCredentialReconciliationChallenge");
4426
4869
  function parseMlsDevCredentialReconciliationComplete(value) {
4427
- return boundary7(() => {
4870
+ return boundary9(() => {
4428
4871
  const input = readMlsDataRecord(value, ["version", "challengeId", "proof"]);
4429
- return bounded7({ version: requireMlsLiteral(input.version, 1), challengeId: requireMlsUuid(input.challengeId), proof: encoded5(input.proof, 64) });
4872
+ return bounded7({ version: requireMlsLiteral(input.version, 1), challengeId: requireMlsUuid(input.challengeId), proof: encoded6(input.proof, 64) });
4430
4873
  });
4431
4874
  }
4432
4875
  __name(parseMlsDevCredentialReconciliationComplete, "parseMlsDevCredentialReconciliationComplete");
4433
4876
  function parseMlsDevCredentialReconciliationReceipt(value) {
4434
- return boundary7(() => {
4877
+ return boundary9(() => {
4435
4878
  const input = readMlsDataRecord(value, ["version", "authorization", "challenge", "observedCredentialGeneration", "observedAtMs"]);
4436
4879
  const challenge = parseMlsDevCredentialReconciliationChallenge(input.challenge);
4437
4880
  const observedCredentialGeneration = requireMlsInteger(input.observedCredentialGeneration), observedAtMs = requireMlsInteger(input.observedAtMs);
4438
- if (observedCredentialGeneration < challenge.expectedCredentialGeneration || observedAtMs < challenge.issuedAtMs || observedAtMs >= challenge.expiresAtMs) invalid9();
4881
+ if (observedCredentialGeneration < challenge.expectedCredentialGeneration || observedAtMs < challenge.issuedAtMs || observedAtMs >= challenge.expiresAtMs) invalid12();
4439
4882
  return bounded7({
4440
4883
  version: requireMlsLiteral(input.version, 1),
4441
4884
  authorization: requireMlsLiteral(input.authorization, "credential_generation_observation_only"),
@@ -4461,51 +4904,51 @@ var MlsDevDeviceCustodyValidationError = class extends Error {
4461
4904
  this.name = "MlsDevDeviceCustodyValidationError";
4462
4905
  }
4463
4906
  };
4464
- var utf86 = new TextEncoder();
4465
- function invalid10() {
4907
+ var utf87 = new TextEncoder();
4908
+ function invalid13() {
4466
4909
  throw new MlsDevDeviceCustodyValidationError();
4467
4910
  }
4468
- __name(invalid10, "invalid");
4469
- function boundary8(read) {
4911
+ __name(invalid13, "invalid");
4912
+ function boundary10(read) {
4470
4913
  try {
4471
4914
  return read();
4472
4915
  } catch {
4473
- return invalid10();
4916
+ return invalid13();
4474
4917
  }
4475
4918
  }
4476
- __name(boundary8, "boundary");
4477
- function bounded8(value, limit) {
4478
- if (utf86.encode(JSON.stringify(value)).length > limit) invalid10();
4919
+ __name(boundary10, "boundary");
4920
+ function bounded8(value, limit2) {
4921
+ if (utf87.encode(JSON.stringify(value)).length > limit2) invalid13();
4479
4922
  return Object.freeze(value);
4480
4923
  }
4481
4924
  __name(bounded8, "bounded");
4482
4925
  function binding2(input) {
4483
4926
  return {
4484
4927
  version: requireMlsLiteral(input.version, 1),
4485
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
4928
+ environmentId: requireMlsEnvironmentId(input.environmentId),
4486
4929
  principal: parseMlsDevEnrollmentPrincipal(input.principal),
4487
4930
  installationId: parseMlsDevInstallationId(input.installationId)
4488
4931
  };
4489
4932
  }
4490
4933
  __name(binding2, "binding");
4491
4934
  function parseMlsDevDeviceBinding(value) {
4492
- return boundary8(() => bounded8(binding2(readMlsDataRecord(value, ["version", "environmentId", "principal", "installationId"])), MLS_DEV_DEVICE_CONTEXT_MAX_BYTES));
4935
+ return boundary10(() => bounded8(binding2(readMlsDataRecord(value, ["version", "environmentId", "principal", "installationId"])), MLS_DEV_DEVICE_CONTEXT_MAX_BYTES));
4493
4936
  }
4494
4937
  __name(parseMlsDevDeviceBinding, "parseMlsDevDeviceBinding");
4495
4938
  function parseMlsDevDeviceContext(value) {
4496
- return boundary8(() => {
4939
+ return boundary10(() => {
4497
4940
  const input = readMlsDataRecord(value, ["version", "environmentId", "principal", "installationId", "revision"]);
4498
4941
  const revision2 = requireMlsInteger(input.revision);
4499
- if (revision2 >= Number.MAX_SAFE_INTEGER) invalid10();
4942
+ if (revision2 >= Number.MAX_SAFE_INTEGER) invalid13();
4500
4943
  return bounded8({ ...binding2(input), revision: revision2 }, MLS_DEV_DEVICE_CONTEXT_MAX_BYTES);
4501
4944
  });
4502
4945
  }
4503
4946
  __name(parseMlsDevDeviceContext, "parseMlsDevDeviceContext");
4504
4947
  function parseMlsDevDeviceCommand(value) {
4505
- return boundary8(() => {
4506
- if (value === null || typeof value !== "object") invalid10();
4948
+ return boundary10(() => {
4949
+ if (value === null || typeof value !== "object") invalid13();
4507
4950
  const descriptor = Object.getOwnPropertyDescriptor(value, "op");
4508
- if (!descriptor || !Object.hasOwn(descriptor, "value")) invalid10();
4951
+ if (!descriptor || !Object.hasOwn(descriptor, "value")) invalid13();
4509
4952
  if (descriptor.value === "create") {
4510
4953
  const input2 = readMlsDataRecord(value, ["op"]);
4511
4954
  return Object.freeze({ op: requireMlsLiteral(input2.op, "create") });
@@ -4521,19 +4964,19 @@ function parseMlsDevDeviceCommand(value) {
4521
4964
  const input2 = readMlsDataRecord(value, ["op", "challenge", "expectedCredentialGeneration"]);
4522
4965
  const challenge2 = parseMlsDevCredentialReconciliationChallenge(input2.challenge);
4523
4966
  const expectedCredentialGeneration2 = requireMlsInteger(input2.expectedCredentialGeneration);
4524
- if (challenge2.expectedCredentialGeneration !== expectedCredentialGeneration2) invalid10();
4967
+ if (challenge2.expectedCredentialGeneration !== expectedCredentialGeneration2) invalid13();
4525
4968
  return bounded8({
4526
4969
  op: requireMlsLiteral(input2.op, "credential_reconciliation_proof"),
4527
4970
  challenge: challenge2,
4528
4971
  expectedCredentialGeneration: expectedCredentialGeneration2
4529
4972
  }, MLS_DEV_DEVICE_COMMAND_MAX_BYTES);
4530
4973
  }
4531
- if (descriptor.value !== "credential_proof") invalid10();
4974
+ if (descriptor.value !== "credential_proof") invalid13();
4532
4975
  const input = readMlsDataRecord(value, ["op", "challenge", "registrationResult", "expectedCredentialGeneration"]);
4533
4976
  const challenge = parseMlsDevCredentialChallenge(input.challenge);
4534
4977
  const registrationResult = parseMlsDevEnrollmentResult(input.registrationResult);
4535
4978
  const expectedCredentialGeneration = requireMlsInteger(input.expectedCredentialGeneration);
4536
- if (expectedCredentialGeneration >= Number.MAX_SAFE_INTEGER || challenge.credential.claims.generation !== expectedCredentialGeneration + 1 || JSON.stringify(challenge.credential.claims.device) !== JSON.stringify(registrationResult.device)) invalid10();
4979
+ if (expectedCredentialGeneration >= Number.MAX_SAFE_INTEGER || challenge.credential.claims.generation !== expectedCredentialGeneration + 1 || JSON.stringify(challenge.credential.claims.device) !== JSON.stringify(registrationResult.device)) invalid13();
4537
4980
  return bounded8({
4538
4981
  op: requireMlsLiteral(input.op, "credential_proof"),
4539
4982
  challenge,
@@ -4543,29 +4986,29 @@ function parseMlsDevDeviceCommand(value) {
4543
4986
  });
4544
4987
  }
4545
4988
  __name(parseMlsDevDeviceCommand, "parseMlsDevDeviceCommand");
4546
- function encoded6(value, bytes) {
4989
+ function encoded7(value, bytes) {
4547
4990
  decodeCanonicalMlsBase64Url(value, bytes);
4548
4991
  return value;
4549
4992
  }
4550
- __name(encoded6, "encoded");
4993
+ __name(encoded7, "encoded");
4551
4994
  function wrapped(value) {
4552
- if (typeof value !== "string" || value.length > MLS_DEV_DEVICE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid10();
4995
+ if (typeof value !== "string" || value.length > MLS_DEV_DEVICE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid13();
4553
4996
  const body = value.slice(3);
4554
- if (body.length < 40 || body.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(body)) invalid10();
4997
+ if (body.length < 40 || body.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(body)) invalid13();
4555
4998
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4556
- if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0) invalid10();
4557
- if (!body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0) invalid10();
4999
+ if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0) invalid13();
5000
+ if (!body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0) invalid13();
4558
5001
  return value;
4559
5002
  }
4560
5003
  __name(wrapped, "wrapped");
4561
5004
  function parseMlsDevDevicePreparation(value, op) {
4562
- return boundary8(() => {
4563
- if (!["create", "enrollment_proof", "credential_proof", "credential_reconciliation_proof"].includes(op)) invalid10();
5005
+ return boundary10(() => {
5006
+ if (!["create", "enrollment_proof", "credential_proof", "credential_reconciliation_proof"].includes(op)) invalid13();
4564
5007
  const input = readMlsDataRecord(value, ["wrappedState", "payload"]);
4565
5008
  const payload = readMlsDataRecord(input.payload, op === "create" ? ["signaturePublicKey"] : ["signaturePublicKey", "proof"]);
4566
5009
  return bounded8({ wrappedState: wrapped(input.wrappedState), payload: Object.freeze({
4567
- signaturePublicKey: encoded6(payload.signaturePublicKey, 32),
4568
- ...op === "create" ? {} : { proof: encoded6(payload.proof, 64) }
5010
+ signaturePublicKey: encoded7(payload.signaturePublicKey, 32),
5011
+ ...op === "create" ? {} : { proof: encoded7(payload.proof, 64) }
4569
5012
  }) }, MLS_DEV_DEVICE_COMMAND_MAX_BYTES);
4570
5013
  });
4571
5014
  }
@@ -4586,56 +5029,56 @@ var MlsDevKeyPackageValidationError = class extends Error {
4586
5029
  this.name = "MlsDevKeyPackageValidationError";
4587
5030
  }
4588
5031
  };
4589
- var utf87 = new TextEncoder();
4590
- function invalid11() {
5032
+ var utf88 = new TextEncoder();
5033
+ function invalid14() {
4591
5034
  throw new MlsDevKeyPackageValidationError();
4592
5035
  }
4593
- __name(invalid11, "invalid");
4594
- function boundary9(read) {
5036
+ __name(invalid14, "invalid");
5037
+ function boundary11(read) {
4595
5038
  try {
4596
5039
  return read();
4597
5040
  } catch {
4598
- return invalid11();
5041
+ return invalid14();
4599
5042
  }
4600
5043
  }
4601
- __name(boundary9, "boundary");
5044
+ __name(boundary11, "boundary");
4602
5045
  function bounded9(value, maximum) {
4603
- if (utf87.encode(JSON.stringify(value)).length > maximum) invalid11();
5046
+ if (utf88.encode(JSON.stringify(value)).length > maximum) invalid14();
4604
5047
  return Object.freeze(value);
4605
5048
  }
4606
5049
  __name(bounded9, "bounded");
4607
- function encoded7(value, bytes) {
5050
+ function encoded8(value, bytes) {
4608
5051
  decodeCanonicalMlsBase64Url(value, bytes);
4609
5052
  return value;
4610
5053
  }
4611
- __name(encoded7, "encoded");
4612
- function wire2(value) {
4613
- if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_KEY_PACKAGE_WIRE_MAX_BYTES * 4 / 3)) invalid11();
5054
+ __name(encoded8, "encoded");
5055
+ function wire3(value) {
5056
+ if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_KEY_PACKAGE_WIRE_MAX_BYTES * 4 / 3)) invalid14();
4614
5057
  const bytes = Math.floor(value.length * 3 / 4);
4615
- if (bytes < 1 || bytes > MLS_DEV_KEY_PACKAGE_WIRE_MAX_BYTES || value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value)) invalid11();
5058
+ if (bytes < 1 || bytes > MLS_DEV_KEY_PACKAGE_WIRE_MAX_BYTES || value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value)) invalid14();
4616
5059
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
4617
- if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid11();
5060
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid14();
4618
5061
  return value;
4619
5062
  }
4620
- __name(wire2, "wire");
5063
+ __name(wire3, "wire");
4621
5064
  function wrapped2(value) {
4622
- if (typeof value !== "string" || value.length > MLS_DEV_KEY_PACKAGE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid11();
5065
+ if (typeof value !== "string" || value.length > MLS_DEV_KEY_PACKAGE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid14();
4623
5066
  const body = value.slice(3);
4624
- if (body.length < 40 || body.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(body)) invalid11();
5067
+ if (body.length < 40 || body.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(body)) invalid14();
4625
5068
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4626
- if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0) invalid11();
4627
- if (!body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0) invalid11();
5069
+ if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0) invalid14();
5070
+ if (!body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0) invalid14();
4628
5071
  const bytes = body.length / 4 * 3 - (body.endsWith("==") ? 2 : body.endsWith("=") ? 1 : 0);
4629
- if (bytes > 128 * 1024 + 28) invalid11();
5072
+ if (bytes > 128 * 1024 + 28) invalid14();
4630
5073
  return value;
4631
5074
  }
4632
5075
  __name(wrapped2, "wrapped");
4633
5076
  function parseMlsDevKeyPackageId(value) {
4634
- return boundary9(() => requireMlsUuid(value));
5077
+ return boundary11(() => requireMlsUuid(value));
4635
5078
  }
4636
5079
  __name(parseMlsDevKeyPackageId, "parseMlsDevKeyPackageId");
4637
5080
  function parseMlsDevKeyPackageCommand(value) {
4638
- return boundary9(() => {
5081
+ return boundary11(() => {
4639
5082
  const input = readMlsDataRecord(value, ["version", "op", "keyPackageId", "credential"]);
4640
5083
  const token2 = parseMlsDevCredentialToken(input.credential);
4641
5084
  parseMlsDevEnrollmentPrincipal(token2.unsigned.claims.device.principal);
@@ -4649,7 +5092,7 @@ function parseMlsDevKeyPackageCommand(value) {
4649
5092
  }
4650
5093
  __name(parseMlsDevKeyPackageCommand, "parseMlsDevKeyPackageCommand");
4651
5094
  function parseMlsDevKeyPackagePayload(value) {
4652
- return boundary9(() => {
5095
+ return boundary11(() => {
4653
5096
  const input = readMlsDataRecord(value, [
4654
5097
  "version",
4655
5098
  "keyPackageId",
@@ -4664,7 +5107,7 @@ function parseMlsDevKeyPackagePayload(value) {
4664
5107
  "expiresAtMs"
4665
5108
  ]);
4666
5109
  const notBeforeMs = requireMlsInteger(input.notBeforeMs), expiresAtMs = requireMlsInteger(input.expiresAtMs);
4667
- if (notBeforeMs % 1e3 !== 0 || expiresAtMs % 1e3 !== 0 || expiresAtMs <= notBeforeMs || expiresAtMs - notBeforeMs > 864e5) invalid11();
5110
+ if (notBeforeMs % 1e3 !== 0 || expiresAtMs % 1e3 !== 0 || expiresAtMs <= notBeforeMs || expiresAtMs - notBeforeMs > 864e5) invalid14();
4668
5111
  return bounded9({
4669
5112
  version: requireMlsLiteral(input.version, 1),
4670
5113
  keyPackageId: requireMlsUuid(input.keyPackageId),
@@ -4672,9 +5115,9 @@ function parseMlsDevKeyPackagePayload(value) {
4672
5115
  credentialId: requireMlsUuid(input.credentialId),
4673
5116
  credentialGeneration: requireMlsInteger(input.credentialGeneration, 1),
4674
5117
  ciphersuite: requireMlsLiteral(input.ciphersuite, 1),
4675
- signaturePublicKey: encoded7(input.signaturePublicKey, 32),
4676
- keyPackage: wire2(input.keyPackage),
4677
- keyPackageRef: encoded7(input.keyPackageRef, 32),
5118
+ signaturePublicKey: encoded8(input.signaturePublicKey, 32),
5119
+ keyPackage: wire3(input.keyPackage),
5120
+ keyPackageRef: encoded8(input.keyPackageRef, 32),
4678
5121
  notBeforeMs,
4679
5122
  expiresAtMs
4680
5123
  }, MLS_DEV_KEY_PACKAGE_PREPARATION_MAX_BYTES);
@@ -4682,7 +5125,7 @@ function parseMlsDevKeyPackagePayload(value) {
4682
5125
  }
4683
5126
  __name(parseMlsDevKeyPackagePayload, "parseMlsDevKeyPackagePayload");
4684
5127
  function parseMlsDevKeyPackagePreparation(value) {
4685
- return boundary9(() => {
5128
+ return boundary11(() => {
4686
5129
  const input = readMlsDataRecord(value, ["wrappedState", "payload"]);
4687
5130
  return bounded9(
4688
5131
  { wrappedState: wrapped2(input.wrappedState), payload: parseMlsDevKeyPackagePayload(input.payload) },
@@ -4692,6 +5135,71 @@ function parseMlsDevKeyPackagePreparation(value) {
4692
5135
  }
4693
5136
  __name(parseMlsDevKeyPackagePreparation, "parseMlsDevKeyPackagePreparation");
4694
5137
 
5138
+ // ../backend-contracts/src/mlsPrincipalAlias.ts
5139
+ var MLS_PRINCIPAL_ALIAS_PREFIX = "mlsa_";
5140
+ var ALIAS_PATTERN = /^mlsa_[A-Za-z0-9_-]{43}$/;
5141
+ var utf89 = new TextEncoder();
5142
+ var domain3 = utf89.encode("canon.mls.principal-alias.v1\0");
5143
+ function invalid15() {
5144
+ throw new Error("INVALID_MLS_PRINCIPAL_ALIAS");
5145
+ }
5146
+ __name(invalid15, "invalid");
5147
+ function isMlsPrincipalAlias(value) {
5148
+ return typeof value === "string" && ALIAS_PATTERN.test(value);
5149
+ }
5150
+ __name(isMlsPrincipalAlias, "isMlsPrincipalAlias");
5151
+ function accountId(value) {
5152
+ if (typeof value !== "string" || value.length < 1 || /[\u0000-\u001f\u007f-\u009f/]/.test(value) || value === "." || value === ".." || utf89.encode(value).length > 512 || /[\ud800-\udfff]/.test(value.replace(/[\ud800-\udbff][\udc00-\udfff]/g, ""))) invalid15();
5153
+ if (ALIAS_PATTERN.test(value)) invalid15();
5154
+ return value;
5155
+ }
5156
+ __name(accountId, "accountId");
5157
+ function parseMlsPrincipalOpening(value) {
5158
+ try {
5159
+ const input = readMlsDataRecord(value, ["type", "accountId", "salt"]);
5160
+ if (input.type !== "human" && input.type !== "ai_agent") invalid15();
5161
+ decodeCanonicalMlsBase64Url(input.salt, 32);
5162
+ return Object.freeze({ type: input.type, accountId: accountId(input.accountId), salt: input.salt });
5163
+ } catch {
5164
+ return invalid15();
5165
+ }
5166
+ }
5167
+ __name(parseMlsPrincipalOpening, "parseMlsPrincipalOpening");
5168
+ function encodeMlsPrincipalAliasInput(environmentId, opening) {
5169
+ const value = parseMlsPrincipalOpening(opening);
5170
+ const environment = utf89.encode(requireMlsEnvironmentId(environmentId));
5171
+ const id7 = utf89.encode(value.accountId);
5172
+ const output = new Uint8Array(domain3.length + 4 + environment.length + 1 + 4 + id7.length + 32);
5173
+ const view = new DataView(output.buffer);
5174
+ let offset = 0;
5175
+ const raw = /* @__PURE__ */ __name((bytes) => {
5176
+ output.set(bytes, offset);
5177
+ offset += bytes.length;
5178
+ }, "raw");
5179
+ const lp = /* @__PURE__ */ __name((bytes) => {
5180
+ view.setUint32(offset, bytes.length);
5181
+ offset += 4;
5182
+ raw(bytes);
5183
+ }, "lp");
5184
+ raw(domain3);
5185
+ lp(environment);
5186
+ output[offset++] = value.type === "human" ? 0 : 1;
5187
+ lp(id7);
5188
+ raw(decodeCanonicalMlsBase64Url(value.salt, 32));
5189
+ return output;
5190
+ }
5191
+ __name(encodeMlsPrincipalAliasInput, "encodeMlsPrincipalAliasInput");
5192
+ function parseMlsRoomIdentities(value) {
5193
+ if (value === null || typeof value !== "object" || Array.isArray(value)) invalid15();
5194
+ const output = /* @__PURE__ */ Object.create(null);
5195
+ for (const [alias, opening] of Object.entries(readMlsDataRecord(value, Object.keys(value)))) {
5196
+ if (!isMlsPrincipalAlias(alias)) invalid15();
5197
+ output[alias] = parseMlsPrincipalOpening(opening);
5198
+ }
5199
+ return Object.freeze(output);
5200
+ }
5201
+ __name(parseMlsRoomIdentities, "parseMlsRoomIdentities");
5202
+
4695
5203
  // ../endpoint/src/runtime-api-origins.generated.ts
4696
5204
  var RUNTIME_API_ORIGINS = {
4697
5205
  "canon-dev-v1": "https://dev.api.canonmail.com",
@@ -4699,76 +5207,86 @@ var RUNTIME_API_ORIGINS = {
4699
5207
  };
4700
5208
 
4701
5209
  // ../endpoint/src/mls-crypto.ts
4702
- var MLS_DEV_DEVICE_HTTP_CONFIGURATION = Object.freeze({
4703
- enrollmentUrl: `${RUNTIME_API_ORIGINS["canon-dev-v1"]}/mls/enrollment`,
4704
- credentialUrl: `${RUNTIME_API_ORIGINS["canon-dev-v1"]}/mls/credential`,
4705
- reconciliationUrl: `${RUNTIME_API_ORIGINS["canon-dev-v1"]}/mls/reconciliation`,
4706
- keyPackagesUrl: `${RUNTIME_API_ORIGINS["canon-dev-v1"]}/mls/key-packages`,
4707
- trustedOrigins: Object.freeze([RUNTIME_API_ORIGINS["canon-dev-v1"]])
4708
- });
4709
- function invalid12() {
5210
+ function mlsDevDeviceHttpConfiguration(environmentId) {
5211
+ if (!isMlsEnvironmentId(environmentId)) invalid16();
5212
+ const origin = RUNTIME_API_ORIGINS[environmentId];
5213
+ return Object.freeze({
5214
+ enrollmentUrl: `${origin}/mls/enrollment`,
5215
+ credentialUrl: `${origin}/mls/credential`,
5216
+ reconciliationUrl: `${origin}/mls/reconciliation`,
5217
+ keyPackagesUrl: `${origin}/mls/key-packages`,
5218
+ trustedOrigins: Object.freeze([origin])
5219
+ });
5220
+ }
5221
+ __name(mlsDevDeviceHttpConfiguration, "mlsDevDeviceHttpConfiguration");
5222
+ function invalid16() {
4710
5223
  throw new Error("MLS_DEV_CLIENT_CONFIGURATION_INVALID");
4711
5224
  }
4712
- __name(invalid12, "invalid");
4713
- function record3(value, keys2) {
4714
- if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) invalid12();
4715
- const fields = Object.getOwnPropertyDescriptors(value);
4716
- if (Reflect.ownKeys(fields).length !== keys2.length || keys2.some((key2) => !Object.hasOwn(fields, key2) || !Object.hasOwn(fields[key2], "value"))) invalid12();
5225
+ __name(invalid16, "invalid");
5226
+ function record4(value, keys2) {
5227
+ if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) invalid16();
5228
+ const fields2 = Object.getOwnPropertyDescriptors(value);
5229
+ if (Reflect.ownKeys(fields2).length !== keys2.length || keys2.some((key) => !Object.hasOwn(fields2, key) || !Object.hasOwn(fields2[key], "value"))) invalid16();
4717
5230
  return value;
4718
5231
  }
4719
- __name(record3, "record");
5232
+ __name(record4, "record");
4720
5233
  function primeOrderPoint(value) {
4721
5234
  const point = ed25519.Point.fromBytes(value, false);
4722
5235
  return !point.isSmallOrder() && point.isTorsionFree();
4723
5236
  }
4724
5237
  __name(primeOrderPoint, "primeOrderPoint");
4725
- function issuerKeys(value) {
4726
- if (!Array.isArray(value) || value.length < 1 || value.length > 8) invalid12();
5238
+ function issuerKeys(value, environmentId, receipt = false) {
5239
+ if (!Array.isArray(value) || value.length < 1 || value.length > 8) invalid16();
4727
5240
  const seen = /* @__PURE__ */ new Set();
4728
- return Object.freeze(Array.from(value, (item) => {
4729
- const key2 = record3(item, ["keyVersion", "signaturePublicKey"]);
4730
- const keyVersion = parseMlsDevIssuerKeyVersion(key2.keyVersion);
4731
- if (seen.has(keyVersion) || typeof key2.signaturePublicKey !== "string" || !primeOrderPoint(decodeCanonicalMlsBase64Url(key2.signaturePublicKey, 32))) invalid12();
5241
+ let environment = environmentId;
5242
+ return Object.freeze(Array.from(value, (item2) => {
5243
+ const key = record4(item2, ["keyVersion", "signaturePublicKey"]);
5244
+ const keyVersion = receipt ? parseMlsDevReceiptKeyVersion(key.keyVersion, environment) : parseMlsDevIssuerKeyVersion(key.keyVersion, environment);
5245
+ environment ??= receipt ? mlsEnvironmentOfReceiptKeyVersion(keyVersion) : mlsEnvironmentOfIssuerKeyVersion(keyVersion);
5246
+ if (seen.has(keyVersion) || typeof key.signaturePublicKey !== "string" || !primeOrderPoint(decodeCanonicalMlsBase64Url(key.signaturePublicKey, 32))) invalid16();
4732
5247
  seen.add(keyVersion);
4733
- return Object.freeze({ keyVersion, signaturePublicKey: key2.signaturePublicKey });
5248
+ return Object.freeze({ keyVersion, signaturePublicKey: key.signaturePublicKey });
4734
5249
  }));
4735
5250
  }
4736
5251
  __name(issuerKeys, "issuerKeys");
4737
5252
  function parseMlsDevClientConfiguration(value) {
4738
5253
  try {
4739
- const input = record3(value, ["version", "environmentId", "enabled", "principalIds", "issuerKeys"]);
4740
- if (input.version !== 1 || input.environmentId !== "canon-dev-v1" || input.enabled !== true || !Array.isArray(input.principalIds) || input.principalIds.length < 1 || input.principalIds.length > 100) invalid12();
4741
- const principalIds = Array.from(input.principalIds, (id6) => parseMlsDevEnrollmentPrincipal({ type: "human", id: id6 }).id);
4742
- if (new Set(principalIds).size !== principalIds.length) invalid12();
5254
+ const listed = !!value && typeof value === "object" && Object.hasOwn(value, "principalIds");
5255
+ const input = record4(value, ["version", "environmentId", "enabled", ...listed ? ["principalIds"] : [], "issuerKeys", "receiptKeys"]);
5256
+ if (input.version !== 1 || !isMlsEnvironmentId(input.environmentId) || input.enabled !== true || listed && (!Array.isArray(input.principalIds) || input.principalIds.length < 1 || input.principalIds.length > 100)) invalid16();
5257
+ const environmentId = input.environmentId;
5258
+ const principalIds = listed ? Array.from(input.principalIds, (id7) => parseMlsDevEnrollmentPrincipal({ type: "human", id: id7 }).id) : void 0;
5259
+ if (principalIds && new Set(principalIds).size !== principalIds.length) invalid16();
4743
5260
  return Object.freeze({
4744
5261
  version: 1,
4745
- environmentId: "canon-dev-v1",
5262
+ environmentId,
4746
5263
  enabled: true,
4747
- principalIds: Object.freeze(principalIds),
4748
- issuerKeys: issuerKeys(input.issuerKeys)
5264
+ ...principalIds ? { principalIds: Object.freeze(principalIds) } : {},
5265
+ issuerKeys: issuerKeys(input.issuerKeys, environmentId),
5266
+ receiptKeys: issuerKeys(input.receiptKeys, environmentId, true)
4749
5267
  });
4750
5268
  } catch {
4751
- return invalid12();
5269
+ return invalid16();
4752
5270
  }
4753
5271
  }
4754
5272
  __name(parseMlsDevClientConfiguration, "parseMlsDevClientConfiguration");
4755
5273
  function createMlsDevCredentialVerifier(options) {
4756
5274
  let trusted;
4757
5275
  try {
4758
- trusted = new Map(issuerKeys(options.issuerKeys).map((key2) => [key2.keyVersion, key2.signaturePublicKey]));
5276
+ trusted = new Map(issuerKeys(options.issuerKeys).map((key) => [key.keyVersion, key.signaturePublicKey]));
4759
5277
  } catch {
4760
- return invalid12();
5278
+ return invalid16();
4761
5279
  }
4762
5280
  const clock = options.clock ?? Date.now;
4763
5281
  return async (value) => {
4764
5282
  try {
4765
5283
  const receipt = parseMlsDevCredentialReceipt(value);
4766
5284
  const parsed = parseMlsDevCredentialToken(receipt.credential);
4767
- const key2 = trusted.get(parsed.unsigned.keyVersion);
5285
+ const key = trusted.get(parsed.unsigned.keyVersion);
4768
5286
  const now = clock();
4769
5287
  const { issuedAtMs, expiresAtMs } = parsed.unsigned.claims;
4770
- if (!key2 || !Number.isSafeInteger(now) || now < issuedAtMs || now >= expiresAtMs) return false;
4771
- const publicKey = decodeCanonicalMlsBase64Url(key2, 32);
5288
+ if (!key || !Number.isSafeInteger(now) || now < issuedAtMs || now >= expiresAtMs) return false;
5289
+ const publicKey = decodeCanonicalMlsBase64Url(key, 32);
4772
5290
  const signature = decodeCanonicalMlsBase64Url(parsed.signature, 64);
4773
5291
  if (!primeOrderPoint(publicKey) || !primeOrderPoint(signature.subarray(0, 32))) return false;
4774
5292
  return ed25519.verify(signature, new TextEncoder().encode(parsed.signingInput), publicKey, { zip215: false });
@@ -4782,7 +5300,16 @@ __name(createMlsDevCredentialVerifier, "createMlsDevCredentialVerifier");
4782
5300
  export {
4783
5301
  __name,
4784
5302
  getCanonEnvironmentContract,
5303
+ CANON_CLIENT_HEADER,
5304
+ CLIENT_UPDATE_REQUIRED,
5305
+ isCanonClientVersion,
5306
+ formatCanonClientHeader,
4785
5307
  sanitizeDownloadFileName,
5308
+ describeAttachment,
5309
+ isCanonMediaOrigin,
5310
+ isCanonUploadUrl,
5311
+ resolveAllowedUploadMimeType,
5312
+ isMlsEnvironmentId,
4786
5313
  MLS_DEV_ENROLLMENT_MAX_BYTES,
4787
5314
  parseMlsDevEnrollmentPrincipal,
4788
5315
  parseMlsDevEnrollmentBegin,
@@ -4799,6 +5326,8 @@ export {
4799
5326
  createMlsDevCredentialSigningInput,
4800
5327
  parseMlsDevCredentialToken,
4801
5328
  parseMlsDevCredentialReceipt,
5329
+ MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW,
5330
+ isMlsDevReceiptClockSkew,
4802
5331
  parseMlsDevGroupFeedEntry,
4803
5332
  parseMlsDevGroupFeedQuery,
4804
5333
  parseMlsDevGroupFeedResult,
@@ -4808,23 +5337,36 @@ export {
4808
5337
  parseMlsDevKeyPackagePublicationReceipt,
4809
5338
  parseMlsDevKeyPackageClaim,
4810
5339
  parseMlsDevKeyPackageClaimReceipt,
5340
+ MLS_DEV_INTERACTION_LIMITS,
5341
+ parseMlsDevInteractionRequestBody,
5342
+ parseMlsDevInteractionResponseBody,
5343
+ parseMlsDevInteractionWithdrawBody,
5344
+ parseMlsDevApplicationPayload,
5345
+ assertMlsDevInteractionPayloadBinding,
5346
+ isMlsDevInteractionAnswerAllowed,
4811
5347
  parseMlsDevGroupCreateConversation,
4812
5348
  parseMlsDevGroupHead,
4813
5349
  parseMlsDevGroupMarker,
4814
5350
  parseMlsDevGroupRoster,
5351
+ parseMlsDevRoomRemoval,
4815
5352
  parseMlsDevGroupControl,
4816
5353
  parseMlsDevGroupAcceptedControl,
5354
+ parseMlsDevGroupAdmissionsResult,
4817
5355
  parseMlsDevGroupQuery,
4818
5356
  parseMlsDevGroupQueryResult,
4819
5357
  parseMlsDevGroupContext,
4820
5358
  parseMlsDevGroupCommand,
4821
5359
  parseMlsDevGroupPreparation,
4822
- MLS_DEV_TEXT_PROTOCOL,
5360
+ MLS_DEV_TEXT_PROTOCOL_V3,
5361
+ isMlsDevTextProtocol,
5362
+ mlsDevProtocolCarriesCards,
5363
+ MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS,
5364
+ MLS_DEV_TEXT_MAX_BYTES,
4823
5365
  parseMlsDevApplicationReceipt,
4824
5366
  parseMlsDevTextPayload,
5367
+ parseMlsDevItemPayload,
4825
5368
  encodeMlsDevApplicationEnvelopeHash,
4826
5369
  RUNTIME_CARD_FIELD_TYPES,
4827
- RUNTIME_CARD_LIMITS,
4828
5370
  RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES,
4829
5371
  readMembershipChangeMetadata,
4830
5372
  formatMembershipChangeNotice,
@@ -4850,36 +5392,20 @@ export {
4850
5392
  ENDPOINT_ID_PATTERN,
4851
5393
  ENDPOINT_ACTION_PATTERN,
4852
5394
  isEndpointOperationReceipt,
5395
+ CONNECTOR_RELAY_INSTALLATION_PREFIX,
5396
+ CONNECTOR_RELAY_INSTALLATION_PATTERN,
5397
+ isConnectorRelayInstallation,
5398
+ isConnectorRelayCredential,
5399
+ CONNECTOR_RELAY_MAX_BODY_BYTES,
5400
+ CONNECTOR_RELAY_MAX_RESPONSE_BYTES,
5401
+ CONNECTOR_RELAY_ANSWER_WITHIN_MS,
5402
+ connectorRelayResponseBytes,
5403
+ ConnectorRelayRequestError,
5404
+ parseConnectorRelayRequest,
4853
5405
  mergeDeliveryObservation,
4854
5406
  projectDeliveryStatus,
4855
5407
  classifyTransferHttpFailure,
4856
5408
  classifyTransferReceipt,
4857
- ARTIFACT_PROTOCOL_VERSION,
4858
- ARTIFACT_PROTOCOL_MIN_VERSION,
4859
- artifactSchemaName,
4860
- ARTIFACT_COMMAND_MAX_BYTES,
4861
- ARTIFACT_STATE_MAX_BYTES,
4862
- ARTIFACT_KINDS,
4863
- ARTIFACT_COMMAND_TYPES,
4864
- ARTIFACT_LIMITS,
4865
- isArtifactId,
4866
- isArtifactKey,
4867
- ArtifactValidationError,
4868
- quoteArtifactText,
4869
- artifactSingleLine,
4870
- roundFormNumber,
4871
- validateFormValue,
4872
- formValuesEqual,
4873
- formatFormValue,
4874
- normalizeFormField,
4875
- normalizeFormCells,
4876
- normalizeFormInput,
4877
- artifactToolInputSchemas,
4878
- parseArtifactCreateAction,
4879
- parseArtifactUpdateAction,
4880
- parseArtifactImageRegion,
4881
- parseArtifactGenerateImageAction,
4882
- parseArtifactAddImageAction,
4883
5409
  MLS_DEV_CREDENTIAL_RECONCILIATION_MAX_BYTES,
4884
5410
  parseMlsDevCredentialReconciliationBegin,
4885
5411
  parseMlsDevCredentialReconciliationChallenge,
@@ -4893,7 +5419,12 @@ export {
4893
5419
  parseMlsDevKeyPackageCommand,
4894
5420
  parseMlsDevKeyPackagePayload,
4895
5421
  parseMlsDevKeyPackagePreparation,
4896
- MLS_DEV_DEVICE_HTTP_CONFIGURATION,
5422
+ MLS_PRINCIPAL_ALIAS_PREFIX,
5423
+ isMlsPrincipalAlias,
5424
+ parseMlsPrincipalOpening,
5425
+ encodeMlsPrincipalAliasInput,
5426
+ parseMlsRoomIdentities,
5427
+ mlsDevDeviceHttpConfiguration,
4897
5428
  parseMlsDevClientConfiguration,
4898
5429
  createMlsDevCredentialVerifier
4899
5430
  };