@canonmsg/agent-sdk 12.0.0 → 12.2.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-HITMISWV.js +4897 -0
  3. package/dist/chunks/{chunk-FPQFTTND.js → chunk-J63YVAKA.js} +1627 -1099
  4. package/dist/chunks/{chunk-OLJ7H4E2.js → chunk-O5C3ZGI4.js} +6363 -7011
  5. package/dist/chunks/{mls-crypto-NZDNSPAO.js → mls-crypto-ITVGUEP7.js} +3 -3
  6. package/dist/cli.js +403 -30
  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 +52 -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 +6 -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 +26 -0
  31. package/dist/internal/backend-contracts/runtimeCardFields.d.ts +0 -4
  32. package/dist/internal/backend-contracts/upload-mime-types.d.ts +17 -0
  33. package/dist/internal/backend-contracts/verbContract.d.ts +23 -19
  34. package/dist/internal/backend-contracts/verbSchemas.d.ts +38 -29
  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 +3 -152
  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 +22 -63
  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/turn-protocol.d.ts +0 -5
  55. package/dist/internal/core/turn-verbosity.d.ts +5 -23
  56. package/dist/internal/core/types.d.ts +0 -292
  57. package/dist/internal/endpoint/engine.d.ts +31 -1
  58. package/dist/internal/endpoint/index.d.ts +1 -1
  59. package/dist/internal/endpoint/media.d.ts +5 -0
  60. package/dist/internal/endpoint/mls-crypto.d.ts +12 -5
  61. package/dist/internal/endpoint/mls-dev-client.d.ts +9 -1
  62. package/dist/internal/endpoint/mls-dev-device.d.ts +2 -0
  63. package/dist/internal/endpoint/mls-dev-groups.d.ts +65 -5
  64. package/dist/internal/endpoint/mls-dev-interactions.d.ts +99 -0
  65. package/dist/internal/endpoint/mls-dev-key-package-service.d.ts +13 -0
  66. package/dist/internal/endpoint/mls-dev-key-packages.d.ts +23 -3
  67. package/dist/internal/endpoint/mls-dev-text.d.ts +67 -0
  68. package/dist/internal/endpoint/mls-dev-transport.d.ts +2 -1
  69. package/dist/internal/endpoint/node-mls-custody-protocol.d.ts +5 -0
  70. package/dist/internal/endpoint/transport.d.ts +6 -1
  71. package/dist/media.js +2 -2
  72. package/dist/runner/errands.d.ts +118 -0
  73. package/dist/runner/mls.d.ts +97 -0
  74. package/dist/runner/relay.d.ts +87 -0
  75. package/dist/runner/runner.d.ts +61 -0
  76. package/dist/runner/types.d.ts +51 -4
  77. package/package.json +1 -1
  78. package/dist/chunks/chunk-6VK4UZHJ.js +0 -2806
  79. package/dist/internal/backend-contracts/workSessions.d.ts +0 -205
  80. package/dist/internal/core/agent-resolver.d.ts +0 -49
  81. package/dist/internal/core/agent-session.d.ts +0 -12
  82. package/dist/internal/core/artifacts.d.ts +0 -262
  83. package/dist/internal/core/attached-native-session.d.ts +0 -174
  84. package/dist/internal/core/attached-session-file-store.d.ts +0 -3
  85. package/dist/internal/core/control-poller.d.ts +0 -221
  86. package/dist/internal/core/exclusive-json-file-store.d.ts +0 -7
  87. package/dist/internal/core/execution-environment.d.ts +0 -55
  88. package/dist/internal/core/group-context.d.ts +0 -25
  89. package/dist/internal/core/inbound-frame.d.ts +0 -64
  90. package/dist/internal/core/local-runtime-catalog.d.ts +0 -131
  91. package/dist/internal/core/message-format.d.ts +0 -13
  92. package/dist/internal/core/native-session-interaction.d.ts +0 -44
  93. package/dist/internal/core/provenance.d.ts +0 -31
  94. package/dist/internal/core/registration-cli.d.ts +0 -40
  95. package/dist/internal/core/stream.d.ts +0 -77
  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;
@@ -118,16 +366,12 @@ function installation(value) {
118
366
  return value;
119
367
  }
120
368
  __name(installation, "installation");
369
+ function isMlsPrincipalId(value) {
370
+ return typeof value === "string" && value.length > 0 && value.length <= 512 && !/[\u0000-\u001f\u007f-\u009f]/.test(value) && !/[\ud800-\udfff]/.test(value.replace(/[\ud800-\udbff][\udc00-\udfff]/g, "")) && utf8.encode(value).length <= 512;
371
+ }
372
+ __name(isMlsPrincipalId, "isMlsPrincipalId");
121
373
  function principalId(value) {
122
- if (typeof value !== "string" || value.length < 1 || value.length > 512 || /[\u0000-\u001f\u007f-\u009f]/.test(value)) invalid2();
123
- for (let index = 0; index < value.length; index++) {
124
- const unit = value.charCodeAt(index);
125
- if (unit >= 55296 && unit <= 56319) {
126
- const next = value.charCodeAt(++index);
127
- if (!(next >= 56320 && next <= 57343)) invalid2();
128
- } else if (unit >= 56320 && unit <= 57343) invalid2();
129
- }
130
- if (utf8.encode(value).length > 512) invalid2();
374
+ if (!isMlsPrincipalId(value)) invalid2();
131
375
  return value;
132
376
  }
133
377
  __name(principalId, "principalId");
@@ -209,7 +453,7 @@ function parseMlsDevEnrollmentChallenge(value) {
209
453
  version: requireMlsLiteral(input.version, 1),
210
454
  challengeId: requireMlsUuid(input.challengeId),
211
455
  deviceId: requireMlsUuid(input.deviceId),
212
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
456
+ environmentId: requireMlsEnvironmentId(input.environmentId),
213
457
  principal: principal(input.principal),
214
458
  installationId: installation(input.installationId),
215
459
  ciphersuite: requireMlsLiteral(input.ciphersuite, 1),
@@ -242,7 +486,7 @@ function parseMlsDevEnrollmentResult(value) {
242
486
  device: Object.freeze({
243
487
  version: requireMlsLiteral(device.version, 1),
244
488
  deviceId: requireMlsUuid(device.deviceId),
245
- environmentId: requireMlsLiteral(device.environmentId, "canon-dev-v1"),
489
+ environmentId: requireMlsEnvironmentId(device.environmentId),
246
490
  principal: principal(device.principal),
247
491
  installationId: installation(device.installationId),
248
492
  ciphersuite: requireMlsLiteral(device.ciphersuite, 1),
@@ -333,11 +577,11 @@ function encoded2(value, bytes) {
333
577
  return value;
334
578
  }
335
579
  __name(encoded2, "encoded");
336
- function parseMlsDevIssuerKeyVersion(value) {
580
+ function parseMlsDevIssuerKeyVersion(value, environmentId) {
337
581
  return boundary2(() => {
338
582
  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();
583
+ const owner = mlsEnvironmentOfIssuerKeyVersion(value);
584
+ if (!owner || environmentId !== void 0 && owner !== environmentId) invalid3();
341
585
  return value;
342
586
  });
343
587
  }
@@ -348,11 +592,12 @@ function parseMlsDevCredentialClaims(value) {
348
592
  const issuedAtMs = requireMlsInteger(input.issuedAtMs);
349
593
  const expiresAtMs = requireMlsInteger(input.expiresAtMs);
350
594
  if (expiresAtMs - issuedAtMs !== MLS_DEV_CREDENTIAL_TTL_MS) invalid3();
595
+ const device = parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: input.device }).device;
351
596
  return bounded2({
352
597
  version: requireMlsLiteral(input.version, 1),
353
598
  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,
599
+ issuer: requireMlsLiteral(input.issuer, mlsEnvironmentProfile(device.environmentId).issuer),
600
+ device,
356
601
  generation: requireMlsInteger(input.generation, 1),
357
602
  issuedAtMs,
358
603
  expiresAtMs
@@ -363,7 +608,9 @@ __name(parseMlsDevCredentialClaims, "parseMlsDevCredentialClaims");
363
608
  function parseMlsDevCredentialUnsigned(value) {
364
609
  return boundary2(() => {
365
610
  const input = readMlsDataRecord(value, ["keyVersion", "claims"]);
366
- return bounded2({ keyVersion: parseMlsDevIssuerKeyVersion(input.keyVersion), claims: parseMlsDevCredentialClaims(input.claims) });
611
+ const keyVersion = parseMlsDevIssuerKeyVersion(input.keyVersion), claims = parseMlsDevCredentialClaims(input.claims);
612
+ if (mlsEnvironmentOfIssuerKeyVersion(keyVersion) !== claims.device.environmentId) invalid3();
613
+ return bounded2({ keyVersion, claims });
367
614
  });
368
615
  }
369
616
  __name(parseMlsDevCredentialUnsigned, "parseMlsDevCredentialUnsigned");
@@ -423,7 +670,7 @@ function parseMlsDevCredentialRevocationReceipt(value) {
423
670
  }
424
671
  __name(parseMlsDevCredentialRevocationReceipt, "parseMlsDevCredentialRevocationReceipt");
425
672
  function signingInput(unsigned2) {
426
- const header = { alg: "Ed25519", typ: "canon-mls-dev-credential+jws", kid: unsigned2.keyVersion };
673
+ const header = { alg: "Ed25519", typ: mlsEnvironmentProfile(unsigned2.claims.device.environmentId).credentialType, kid: unsigned2.keyVersion };
427
674
  const result = encodeCanonicalMlsBase64Url(utf82.encode(JSON.stringify(header))) + "." + encodeCanonicalMlsBase64Url(utf82.encode(JSON.stringify(unsigned2.claims)));
428
675
  if (result.length > MLS_DEV_CREDENTIAL_MAX_BYTES) invalid3();
429
676
  return result;
@@ -445,8 +692,8 @@ function parseMlsDevCredentialSigningInput(value) {
445
692
  if (parts.length !== 2) invalid3();
446
693
  const header = readMlsDataRecord(jsonSegment(parts[0]), ["alg", "typ", "kid"]);
447
694
  requireMlsLiteral(header.alg, "Ed25519");
448
- requireMlsLiteral(header.typ, "canon-mls-dev-credential+jws");
449
695
  const unsigned2 = parseMlsDevCredentialUnsigned({ keyVersion: header.kid, claims: jsonSegment(parts[1]) });
696
+ requireMlsLiteral(header.typ, mlsEnvironmentProfile(unsigned2.claims.device.environmentId).credentialType);
450
697
  if (signingInput(unsigned2) !== value) invalid3();
451
698
  return unsigned2;
452
699
  });
@@ -476,6 +723,54 @@ function parseMlsDevCredentialReceipt(value) {
476
723
  }
477
724
  __name(parseMlsDevCredentialReceipt, "parseMlsDevCredentialReceipt");
478
725
 
726
+ // ../backend-contracts/src/mlsDevFeedReceipt.ts
727
+ var MlsDevFeedReceiptValidationError = class extends Error {
728
+ static {
729
+ __name(this, "MlsDevFeedReceiptValidationError");
730
+ }
731
+ code = "INVALID_MLS_DEV_FEED_RECEIPT";
732
+ constructor() {
733
+ super("INVALID_MLS_DEV_FEED_RECEIPT");
734
+ this.name = "MlsDevFeedReceiptValidationError";
735
+ }
736
+ };
737
+ function invalid4() {
738
+ throw new MlsDevFeedReceiptValidationError();
739
+ }
740
+ __name(invalid4, "invalid");
741
+ function boundary3(read) {
742
+ try {
743
+ return read();
744
+ } catch {
745
+ return invalid4();
746
+ }
747
+ }
748
+ __name(boundary3, "boundary");
749
+ function parseMlsDevReceiptKeyVersion(value, environmentId) {
750
+ return boundary3(() => {
751
+ if (typeof value !== "string" || value.length > 200) invalid4();
752
+ const owner = mlsEnvironmentOfReceiptKeyVersion(value);
753
+ if (!owner || environmentId !== void 0 && owner !== environmentId) invalid4();
754
+ return value;
755
+ });
756
+ }
757
+ __name(parseMlsDevReceiptKeyVersion, "parseMlsDevReceiptKeyVersion");
758
+ function parseMlsDevFeedReceiptProof(value) {
759
+ return boundary3(() => {
760
+ const input = readMlsDataRecord(value, ["keyVersion", "signature"]);
761
+ decodeCanonicalMlsBase64Url(input.signature, 64);
762
+ return Object.freeze({ keyVersion: parseMlsDevReceiptKeyVersion(input.keyVersion), signature: input.signature });
763
+ });
764
+ }
765
+ __name(parseMlsDevFeedReceiptProof, "parseMlsDevFeedReceiptProof");
766
+ var MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW = "MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW";
767
+ function isMlsDevReceiptClockSkew(value) {
768
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
769
+ const keys2 = Object.keys(value).sort().join(), input = value;
770
+ 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;
771
+ }
772
+ __name(isMlsDevReceiptClockSkew, "isMlsDevReceiptClockSkew");
773
+
479
774
  // ../backend-contracts/src/mlsDevGroupFeed.ts
480
775
  var MLS_DEV_GROUP_FEED_MAX_ENTRIES = 4;
481
776
  var MLS_DEV_GROUP_FEED_MAX_BYTES = 4 * 1024 * 1024;
@@ -489,99 +784,104 @@ var MlsDevGroupFeedValidationError = class extends Error {
489
784
  this.name = "MlsDevGroupFeedValidationError";
490
785
  }
491
786
  };
492
- function invalid4() {
787
+ function invalid5() {
493
788
  throw new MlsDevGroupFeedValidationError();
494
789
  }
495
- __name(invalid4, "invalid");
496
- function boundary3(read) {
790
+ __name(invalid5, "invalid");
791
+ function boundary4(read) {
497
792
  try {
498
793
  return read();
499
794
  } catch {
500
- return invalid4();
795
+ return invalid5();
501
796
  }
502
797
  }
503
- __name(boundary3, "boundary");
798
+ __name(boundary4, "boundary");
504
799
  function id(value) {
505
800
  if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..")
506
- invalid4();
801
+ invalid5();
507
802
  return value;
508
803
  }
509
804
  __name(id, "id");
510
805
  function boolean(value) {
511
806
  if (typeof value !== "boolean")
512
- invalid4();
807
+ invalid5();
513
808
  return value;
514
809
  }
515
810
  __name(boolean, "boolean");
516
811
  function bounded3(value) {
517
812
  if (new TextEncoder().encode(JSON.stringify(value)).length > MLS_DEV_GROUP_FEED_MAX_BYTES)
518
- invalid4();
813
+ invalid5();
519
814
  return Object.freeze(value);
520
815
  }
521
816
  __name(bounded3, "bounded");
522
817
  function array(value) {
523
818
  if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > MLS_DEV_GROUP_FEED_MAX_ENTRIES)
524
- invalid4();
819
+ invalid5();
525
820
  const descriptors = Object.getOwnPropertyDescriptors(value);
526
821
  if (Reflect.ownKeys(descriptors).length !== value.length + 1)
527
- invalid4();
822
+ invalid5();
528
823
  return Array.from({ length: value.length }, (_, index) => {
529
824
  const field = descriptors[index];
530
825
  if (!field || !field.enumerable || !Object.hasOwn(field, "value"))
531
- invalid4();
826
+ invalid5();
532
827
  return field.value;
533
828
  });
534
829
  }
535
830
  __name(array, "array");
536
831
  function parseMlsDevGroupFeedEntry(value) {
537
- return boundary3(() => {
538
- const input = readMlsDataRecord(value, ["version", "ordinal", "kind", "accepted"], ["version", "ordinal", "kind", "receipt", "envelope"]);
832
+ return boundary4(() => {
833
+ const signed = value !== null && typeof value === "object" && Object.hasOwn(value, "receiptProof") ? ["receiptProof"] : [];
834
+ const input = readMlsDataRecord(value, ["version", "ordinal", "kind", "accepted", ...signed], ["version", "ordinal", "kind", "receipt", "envelope", ...signed]);
539
835
  const version = requireMlsLiteral(input.version, 1), ordinal = requireMlsInteger(input.ordinal, 1);
836
+ const proof = signed.length ? { receiptProof: parseMlsDevFeedReceiptProof(input.receiptProof) } : {};
540
837
  if (input.kind === "control") {
541
838
  if (!Object.hasOwn(input, "accepted"))
542
- invalid4();
543
- return bounded3({ version, ordinal, kind: "control", accepted: parseMlsDevGroupAcceptedControl(input.accepted) });
839
+ invalid5();
840
+ return bounded3({ version, ordinal, kind: "control", accepted: parseMlsDevGroupAcceptedControl(input.accepted), ...proof });
544
841
  }
545
842
  const kind = requireMlsLiteral(input.kind, "application"), receipt = parseMlsDevApplicationReceipt(input.receipt), envelope = parseMlsDevApplicationEnvelope(input.envelope);
546
843
  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 });
844
+ invalid5();
845
+ return bounded3({ version, ordinal, kind, receipt, envelope, ...proof });
549
846
  });
550
847
  }
551
848
  __name(parseMlsDevGroupFeedEntry, "parseMlsDevGroupFeedEntry");
552
849
  function parseMlsDevGroupFeedQuery(value) {
553
- return boundary3(() => {
850
+ return boundary4(() => {
554
851
  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();
852
+ const limit2 = requireMlsInteger(input.limit, 1);
853
+ if (limit2 > MLS_DEV_GROUP_FEED_MAX_ENTRIES)
854
+ invalid5();
558
855
  parseMlsDevCredentialToken(input.credential);
559
- return Object.freeze({ version: requireMlsLiteral(input.version, 1), conversationId: id(input.conversationId), credential: input.credential, afterOrdinal: requireMlsInteger(input.afterOrdinal), limit });
856
+ return Object.freeze({ version: requireMlsLiteral(input.version, 1), conversationId: id(input.conversationId), credential: input.credential, afterOrdinal: requireMlsInteger(input.afterOrdinal), limit: limit2 });
560
857
  });
561
858
  }
562
859
  __name(parseMlsDevGroupFeedQuery, "parseMlsDevGroupFeedQuery");
563
860
  function parseMlsDevGroupFeedResult(value) {
564
- return boundary3(() => {
861
+ return boundary4(() => {
565
862
  const input = readMlsDataRecord(value, ["version", "protocol", "conversationId", "marker", "membershipRevision", "admissionId", "roster", "minimumOrdinal", "latestOrdinal", "nextOrdinal", "entries", "hasMore", "terminal"]);
566
863
  const conversationId = id(input.conversationId), marker = input.marker === null ? null : parseMlsDevGroupMarker(input.marker);
567
864
  const minimumOrdinal = input.minimumOrdinal === null ? null : requireMlsInteger(input.minimumOrdinal, 1);
568
865
  const latestOrdinal = requireMlsInteger(input.latestOrdinal), nextOrdinal = requireMlsInteger(input.nextOrdinal);
569
866
  const entries = array(input.entries).map(parseMlsDevGroupFeedEntry), hasMore = boolean(input.hasMore), terminal = boolean(input.terminal);
570
867
  if (nextOrdinal > latestOrdinal || minimumOrdinal !== null && minimumOrdinal > latestOrdinal || minimumOrdinal === null && (entries.length || nextOrdinal || hasMore || terminal) || !marker && (latestOrdinal || minimumOrdinal !== null || entries.length || terminal))
571
- invalid4();
868
+ invalid5();
869
+ const protocol = isMlsDevTextProtocol(input.protocol) ? input.protocol : invalid5();
572
870
  for (let i = 0; i < entries.length; i++) {
573
871
  const entry = entries[i], subject = entry.kind === "control" ? entry.accepted.control : entry.envelope;
872
+ if (entry.kind === "application" && entry.envelope.interaction && !mlsDevProtocolCarriesCards(protocol))
873
+ invalid5();
574
874
  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();
875
+ invalid5();
576
876
  const head = entry.kind === "control" ? entry.accepted.head : entry.receipt.head;
577
877
  if (head.sequence > marker.head.sequence || head.epoch > marker.head.epoch)
578
- invalid4();
878
+ invalid5();
579
879
  }
580
880
  if (entries.length && entries.at(-1).ordinal !== nextOrdinal || hasMore !== (minimumOrdinal !== null && nextOrdinal < latestOrdinal))
581
- invalid4();
881
+ invalid5();
582
882
  return bounded3({
583
883
  version: requireMlsLiteral(input.version, 1),
584
- protocol: requireMlsLiteral(input.protocol, MLS_DEV_TEXT_PROTOCOL),
884
+ protocol,
585
885
  conversationId,
586
886
  marker,
587
887
  membershipRevision: requireMlsInteger(input.membershipRevision),
@@ -611,25 +911,25 @@ var MlsDevKeyPackagesValidationError = class extends Error {
611
911
  this.name = "MlsDevKeyPackagesValidationError";
612
912
  }
613
913
  };
614
- function invalid5() {
914
+ function invalid6() {
615
915
  throw new MlsDevKeyPackagesValidationError();
616
916
  }
617
- __name(invalid5, "invalid");
618
- function boundary4(read) {
917
+ __name(invalid6, "invalid");
918
+ function boundary5(read) {
619
919
  try {
620
920
  return read();
621
921
  } catch {
622
- return invalid5();
922
+ return invalid6();
623
923
  }
624
924
  }
625
- __name(boundary4, "boundary");
925
+ __name(boundary5, "boundary");
626
926
  function bounded4(value) {
627
- if (new TextEncoder().encode(JSON.stringify(value)).length > MLS_DEV_KEY_PACKAGES_MAX_BYTES) invalid5();
927
+ if (new TextEncoder().encode(JSON.stringify(value)).length > MLS_DEV_KEY_PACKAGES_MAX_BYTES) invalid6();
628
928
  return Object.freeze(value);
629
929
  }
630
930
  __name(bounded4, "bounded");
631
931
  function id2(value) {
632
- if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..") invalid5();
932
+ if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..") invalid6();
633
933
  return value;
634
934
  }
635
935
  __name(id2, "id");
@@ -639,18 +939,18 @@ function ref(value) {
639
939
  }
640
940
  __name(ref, "ref");
641
941
  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();
942
+ return boundary5(() => {
943
+ if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_KEY_PACKAGE_TLS_MAX_BYTES * 4 / 3)) invalid6();
644
944
  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();
945
+ 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
946
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
647
- if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid5();
947
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid6();
648
948
  return value;
649
949
  });
650
950
  }
651
951
  __name(parseMlsDevKeyPackageWire, "parseMlsDevKeyPackageWire");
652
952
  function parseMlsDevKeyPackageClaimPreconditions(value) {
653
- return boundary4(() => {
953
+ return boundary5(() => {
654
954
  const input = readMlsDataRecord(value, ["conversationId", "membershipRevision", "admissionId", "targetAdmissionId"]);
655
955
  return Object.freeze({
656
956
  conversationId: id2(input.conversationId),
@@ -662,17 +962,17 @@ function parseMlsDevKeyPackageClaimPreconditions(value) {
662
962
  }
663
963
  __name(parseMlsDevKeyPackageClaimPreconditions, "parseMlsDevKeyPackageClaimPreconditions");
664
964
  function parseMlsDevKeyPackagePublish(value) {
665
- return boundary4(() => {
965
+ return boundary5(() => {
666
966
  const input = readMlsDataRecord(value, ["version", "requestId", "keyPackage"]);
667
967
  return bounded4({ version: requireMlsLiteral(input.version, 1), requestId: requireMlsUuid(input.requestId), keyPackage: parseMlsDevKeyPackageWire(input.keyPackage) });
668
968
  });
669
969
  }
670
970
  __name(parseMlsDevKeyPackagePublish, "parseMlsDevKeyPackagePublish");
671
971
  function parseMlsDevKeyPackagePublicationReceipt(value) {
672
- return boundary4(() => {
972
+ return boundary5(() => {
673
973
  const input = readMlsDataRecord(value, ["version", "authorization", "requestId", "keyPackageRef", "deviceId", "publishedAtMs", "expiresAtMs"]);
674
974
  const publishedAtMs = requireMlsInteger(input.publishedAtMs), expiresAtMs = requireMlsInteger(input.expiresAtMs);
675
- if (publishedAtMs >= expiresAtMs) invalid5();
975
+ if (publishedAtMs >= expiresAtMs) invalid6();
676
976
  return bounded4({
677
977
  version: requireMlsLiteral(input.version, 1),
678
978
  authorization: requireMlsLiteral(input.authorization, "key_package_publication_only"),
@@ -686,7 +986,7 @@ function parseMlsDevKeyPackagePublicationReceipt(value) {
686
986
  }
687
987
  __name(parseMlsDevKeyPackagePublicationReceipt, "parseMlsDevKeyPackagePublicationReceipt");
688
988
  function parseMlsDevKeyPackageClaim(value) {
689
- return boundary4(() => {
989
+ return boundary5(() => {
690
990
  const input = readMlsDataRecord(value, ["version", "requestId", "claimantCredential", "recipientDeviceId", "preconditions"]);
691
991
  parseMlsDevCredentialToken(input.claimantCredential);
692
992
  return bounded4({
@@ -700,7 +1000,7 @@ function parseMlsDevKeyPackageClaim(value) {
700
1000
  }
701
1001
  __name(parseMlsDevKeyPackageClaim, "parseMlsDevKeyPackageClaim");
702
1002
  function parseMlsDevKeyPackageClaimReceipt(value) {
703
- return boundary4(() => {
1003
+ return boundary5(() => {
704
1004
  const input = readMlsDataRecord(value, [
705
1005
  "version",
706
1006
  "authorization",
@@ -713,7 +1013,7 @@ function parseMlsDevKeyPackageClaimReceipt(value) {
713
1013
  "claimedAtMs"
714
1014
  ]);
715
1015
  const claimantDeviceId = requireMlsUuid(input.claimantDeviceId), recipientDeviceId = requireMlsUuid(input.recipientDeviceId);
716
- if (claimantDeviceId === recipientDeviceId) invalid5();
1016
+ if (claimantDeviceId === recipientDeviceId) invalid6();
717
1017
  return bounded4({
718
1018
  version: requireMlsLiteral(input.version, 1),
719
1019
  authorization: requireMlsLiteral(input.authorization, "key_package_claim_only"),
@@ -729,6 +1029,228 @@ function parseMlsDevKeyPackageClaimReceipt(value) {
729
1029
  }
730
1030
  __name(parseMlsDevKeyPackageClaimReceipt, "parseMlsDevKeyPackageClaimReceipt");
731
1031
 
1032
+ // ../backend-contracts/src/mlsDevInteraction.ts
1033
+ var MLS_DEV_INTERACTION_LIMITS = Object.freeze({ title: 200, details: 8e3, options: 10, optionLabel: 120, text: 4e3 });
1034
+ var MLS_DEV_SECRET_ANSWER_MAX_BYTES = MLS_DEV_INTERACTION_LIMITS.text * 4 + 16;
1035
+ var MLS_DEV_INTERACTION_WITHDRAW_REASONS = ["stopped", "turn_ended", "expired", "restart"];
1036
+ var MlsDevInteractionValidationError = class extends Error {
1037
+ static {
1038
+ __name(this, "MlsDevInteractionValidationError");
1039
+ }
1040
+ code = "INVALID_MLS_DEV_INTERACTION";
1041
+ constructor() {
1042
+ super("INVALID_MLS_DEV_INTERACTION");
1043
+ this.name = "MlsDevInteractionValidationError";
1044
+ }
1045
+ };
1046
+ var utf83 = new TextEncoder();
1047
+ function invalid7() {
1048
+ throw new MlsDevInteractionValidationError();
1049
+ }
1050
+ __name(invalid7, "invalid");
1051
+ function boundary6(read) {
1052
+ try {
1053
+ return read();
1054
+ } catch {
1055
+ return invalid7();
1056
+ }
1057
+ }
1058
+ __name(boundary6, "boundary");
1059
+ function id3(value) {
1060
+ if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..") invalid7();
1061
+ return value;
1062
+ }
1063
+ __name(id3, "id");
1064
+ function interactionId(value) {
1065
+ if (typeof value !== "string" || !MLS_DEV_INTERACTION_ID_PATTERN.test(value) || value === "." || value === "..") invalid7();
1066
+ return value;
1067
+ }
1068
+ __name(interactionId, "interactionId");
1069
+ function encoded3(value, bytes) {
1070
+ decodeCanonicalMlsBase64Url(value, bytes);
1071
+ return value;
1072
+ }
1073
+ __name(encoded3, "encoded");
1074
+ function wire(value, min, max) {
1075
+ if (typeof value !== "string" || !/^[A-Za-z0-9_-]*$/.test(value) || value.length % 4 === 1) invalid7();
1076
+ const bytes = Math.floor(value.length * 3 / 4);
1077
+ if (bytes < min || bytes > max) invalid7();
1078
+ const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
1079
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid7();
1080
+ return value;
1081
+ }
1082
+ __name(wire, "wire");
1083
+ function text(value, max) {
1084
+ if (typeof value !== "string" || !value.trim() || [...value].length > max || new TextDecoder("utf-8", { fatal: true }).decode(utf83.encode(value)) !== value) invalid7();
1085
+ return value;
1086
+ }
1087
+ __name(text, "text");
1088
+ function boolean2(value) {
1089
+ if (typeof value !== "boolean") invalid7();
1090
+ return value;
1091
+ }
1092
+ __name(boolean2, "boolean");
1093
+ function array2(value, min, max) {
1094
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length < min || value.length > max) invalid7();
1095
+ const descriptors = Object.getOwnPropertyDescriptors(value);
1096
+ if (Reflect.ownKeys(descriptors).length !== value.length + 1) invalid7();
1097
+ return Array.from({ length: value.length }, (_, index) => {
1098
+ const field = descriptors[index];
1099
+ if (!field || !field.enumerable || !Object.hasOwn(field, "value")) invalid7();
1100
+ return field.value;
1101
+ });
1102
+ }
1103
+ __name(array2, "array");
1104
+ function closed(value, required, optional) {
1105
+ if (value === null || typeof value !== "object" || Array.isArray(value)) invalid7();
1106
+ const present2 = Reflect.ownKeys(value);
1107
+ if (present2.some((key) => typeof key !== "string" || !required.includes(key) && !optional.includes(key))) invalid7();
1108
+ return readMlsDataRecord(value, present2);
1109
+ }
1110
+ __name(closed, "closed");
1111
+ function ordered(value) {
1112
+ return Object.freeze(Object.fromEntries(Object.entries(value).filter(([, field]) => field !== void 0)));
1113
+ }
1114
+ __name(ordered, "ordered");
1115
+ function parseMlsDevInteractionRequestBody(value) {
1116
+ return boundary6(() => {
1117
+ const input = closed(
1118
+ value,
1119
+ ["requestId", "kind", "title", "responderIds", "expiresAtMs"],
1120
+ ["details", "options", "multiple", "risk", "allowSession", "scopeKey", "secretKey"]
1121
+ );
1122
+ const kind = input.kind;
1123
+ if (typeof kind !== "string" || !MLS_DEV_INTERACTION_KINDS.includes(kind)) invalid7();
1124
+ const has = /* @__PURE__ */ __name((key) => Object.hasOwn(input, key), "has");
1125
+ const options = has("options") ? array2(input.options, 1, MLS_DEV_INTERACTION_LIMITS.options).map((option) => {
1126
+ const fields2 = readMlsDataRecord(option, ["id", "label"]);
1127
+ if (typeof fields2.id !== "string" || !/^[A-Za-z0-9_.:-]{1,64}$/.test(fields2.id)) invalid7();
1128
+ return Object.freeze({ id: fields2.id, label: text(fields2.label, MLS_DEV_INTERACTION_LIMITS.optionLabel) });
1129
+ }) : void 0;
1130
+ if (options && new Set(options.map((option) => option.id)).size !== options.length) invalid7();
1131
+ const binding3 = parseMlsDevInteractionBinding({ role: "request", requestId: input.requestId, kind, responderIds: input.responderIds, expiresAtMs: input.expiresAtMs });
1132
+ if (binding3.role !== "request") invalid7();
1133
+ if (kind !== "approval" && ["risk", "allowSession", "scopeKey"].some(has)) invalid7();
1134
+ if (kind !== "question" && (has("options") || has("multiple"))) invalid7();
1135
+ if (has("multiple") && !options) invalid7();
1136
+ if (kind === "secret" !== has("secretKey")) invalid7();
1137
+ const allowSession = has("allowSession") ? boolean2(input.allowSession) : void 0;
1138
+ if (has("scopeKey") && (typeof input.scopeKey !== "string" || !/^[A-Za-z0-9_:-]{1,64}$/.test(input.scopeKey))) invalid7();
1139
+ if (allowSession === true && !has("scopeKey")) invalid7();
1140
+ if (has("risk") && input.risk !== "normal" && input.risk !== "destructive") invalid7();
1141
+ const secretKey = has("secretKey") ? (() => {
1142
+ const key = readMlsDataRecord(input.secretKey, ["kem", "publicKey"]);
1143
+ return Object.freeze({ kem: requireMlsLiteral(key.kem, "x25519"), publicKey: encoded3(key.publicKey, 32) });
1144
+ })() : void 0;
1145
+ return ordered({
1146
+ requestId: binding3.requestId,
1147
+ kind: binding3.kind,
1148
+ title: text(input.title, MLS_DEV_INTERACTION_LIMITS.title),
1149
+ details: has("details") ? text(input.details, MLS_DEV_INTERACTION_LIMITS.details) : void 0,
1150
+ options: options ? Object.freeze(options) : void 0,
1151
+ multiple: has("multiple") ? boolean2(input.multiple) : void 0,
1152
+ risk: input.risk,
1153
+ allowSession,
1154
+ scopeKey: input.scopeKey,
1155
+ responderIds: binding3.responderIds,
1156
+ expiresAtMs: binding3.expiresAtMs,
1157
+ secretKey
1158
+ });
1159
+ });
1160
+ }
1161
+ __name(parseMlsDevInteractionRequestBody, "parseMlsDevInteractionRequestBody");
1162
+ function parseMlsDevInteractionAnswer(value) {
1163
+ return boundary6(() => {
1164
+ if (value === null || typeof value !== "object" || Array.isArray(value)) invalid7();
1165
+ const keys2 = Reflect.ownKeys(value);
1166
+ if (keys2.includes("decision")) {
1167
+ const input = readMlsDataRecord(value, ["decision", "scope"]);
1168
+ if (input.decision !== "allow" && input.decision !== "deny" || input.scope !== "once" && input.scope !== "session") invalid7();
1169
+ return Object.freeze({ decision: input.decision, scope: input.scope });
1170
+ }
1171
+ if (keys2.includes("choices")) {
1172
+ const choices = array2(readMlsDataRecord(value, ["choices"]).choices, 1, MLS_DEV_INTERACTION_LIMITS.options).map((choice) => {
1173
+ if (typeof choice !== "string" || !/^[A-Za-z0-9_.:-]{1,64}$/.test(choice)) invalid7();
1174
+ return choice;
1175
+ });
1176
+ if (new Set(choices).size !== choices.length) invalid7();
1177
+ return Object.freeze({ choices: Object.freeze(choices) });
1178
+ }
1179
+ if (keys2.includes("text")) return Object.freeze({ text: text(readMlsDataRecord(value, ["text"]).text, MLS_DEV_INTERACTION_LIMITS.text) });
1180
+ if (keys2.includes("sealed")) {
1181
+ const sealed = readMlsDataRecord(readMlsDataRecord(value, ["sealed"]).sealed, ["enc", "ciphertext"]);
1182
+ return Object.freeze({ sealed: Object.freeze({ enc: encoded3(sealed.enc, 32), ciphertext: wire(sealed.ciphertext, 17, MLS_DEV_SECRET_ANSWER_MAX_BYTES) }) });
1183
+ }
1184
+ if (readMlsDataRecord(value, ["cancelled"]).cancelled !== true) invalid7();
1185
+ return Object.freeze({ cancelled: true });
1186
+ });
1187
+ }
1188
+ __name(parseMlsDevInteractionAnswer, "parseMlsDevInteractionAnswer");
1189
+ function parseMlsDevInteractionResponseBody(value) {
1190
+ return boundary6(() => {
1191
+ const input = readMlsDataRecord(value, ["requestId", "agentId", "answer"]);
1192
+ return Object.freeze({ requestId: interactionId(input.requestId), agentId: id3(input.agentId), answer: parseMlsDevInteractionAnswer(input.answer) });
1193
+ });
1194
+ }
1195
+ __name(parseMlsDevInteractionResponseBody, "parseMlsDevInteractionResponseBody");
1196
+ function parseMlsDevInteractionWithdrawBody(value) {
1197
+ return boundary6(() => {
1198
+ const input = readMlsDataRecord(value, ["requestId", "reason"]);
1199
+ if (!MLS_DEV_INTERACTION_WITHDRAW_REASONS.includes(input.reason)) invalid7();
1200
+ return Object.freeze({ requestId: interactionId(input.requestId), reason: input.reason });
1201
+ });
1202
+ }
1203
+ __name(parseMlsDevInteractionWithdrawBody, "parseMlsDevInteractionWithdrawBody");
1204
+ var payloadFields = ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId"];
1205
+ function parseMlsDevApplicationPayload(value) {
1206
+ return boundary6(() => {
1207
+ const kind = value && typeof value === "object" ? Object.getOwnPropertyDescriptor(value, "kind") : void 0;
1208
+ if (!kind || !Object.hasOwn(kind, "value")) invalid7();
1209
+ if (kind.value === "text") return parseMlsDevTextPayload(value);
1210
+ if (kind.value === "item") return parseMlsDevItemPayload(value);
1211
+ const input = readMlsDataRecord(value, [...payloadFields, "interaction"]);
1212
+ const ids = {
1213
+ version: requireMlsLiteral(input.version, 1),
1214
+ kind: input.kind,
1215
+ conversationId: id3(input.conversationId),
1216
+ groupId: encoded3(input.groupId, 32),
1217
+ messageId: id3(input.messageId),
1218
+ operationId: id3(input.operationId),
1219
+ senderDeviceId: requireMlsUuid(input.senderDeviceId)
1220
+ };
1221
+ if (ids.messageId.startsWith("membership-")) invalid7();
1222
+ const interaction = kind.value === "interaction.request" ? parseMlsDevInteractionRequestBody(input.interaction) : kind.value === "interaction.response" ? parseMlsDevInteractionResponseBody(input.interaction) : kind.value === "interaction.withdraw" ? parseMlsDevInteractionWithdrawBody(input.interaction) : invalid7();
1223
+ const payload = Object.freeze({ ...ids, interaction });
1224
+ if (utf83.encode(JSON.stringify(payload)).length > MLS_DEV_TEXT_MAX_BYTES) invalid7();
1225
+ return payload;
1226
+ });
1227
+ }
1228
+ __name(parseMlsDevApplicationPayload, "parseMlsDevApplicationPayload");
1229
+ function assertMlsDevInteractionPayloadBinding(payload, binding3) {
1230
+ boundary6(() => {
1231
+ if (payload.kind === "text" || payload.kind === "item") {
1232
+ if (binding3 !== void 0) invalid7();
1233
+ return;
1234
+ }
1235
+ if (!binding3 || payload.interaction.requestId !== binding3.requestId) invalid7();
1236
+ if (payload.kind === "interaction.request") {
1237
+ 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();
1238
+ } else if (payload.kind === "interaction.response") {
1239
+ if (binding3.role !== "response" || payload.interaction.agentId !== binding3.agentId) invalid7();
1240
+ } else if (binding3.role !== "withdraw") invalid7();
1241
+ });
1242
+ }
1243
+ __name(assertMlsDevInteractionPayloadBinding, "assertMlsDevInteractionPayloadBinding");
1244
+ function isMlsDevInteractionAnswerAllowed(request, answer) {
1245
+ if ("cancelled" in answer) return request.kind !== "approval";
1246
+ if (request.kind === "approval") return "decision" in answer && (answer.scope !== "session" || request.allowSession === true);
1247
+ if (request.kind === "secret") return "sealed" in answer;
1248
+ if ("text" in answer) return !request.options;
1249
+ if (!("choices" in answer) || !request.options) return false;
1250
+ return (request.multiple === true || answer.choices.length === 1) && answer.choices.every((choice) => request.options.some((option) => option.id === choice));
1251
+ }
1252
+ __name(isMlsDevInteractionAnswerAllowed, "isMlsDevInteractionAnswerAllowed");
1253
+
732
1254
  // ../backend-contracts/src/mlsDevGroup.ts
733
1255
  var MLS_DEV_GROUP_ROSTER_MAX = 32;
734
1256
  var MLS_DEV_GROUP_TLS_MAX_BYTES = 256 * 1024;
@@ -737,6 +1259,7 @@ var MLS_DEV_GROUP_WRAPPED_MAX_BYTES = 3 * 1024 * 1024;
737
1259
  var MLS_DEV_GROUP_PREPARATION_MAX_BYTES = 4 * 1024 * 1024;
738
1260
  var MLS_DEV_GROUP_QUERY_MAX_BYTES = 4 * 1024 * 1024;
739
1261
  var MLS_DEV_GROUP_QUERY_MAX_CONTROLS = 4;
1262
+ var MLS_DEV_GROUP_ADMISSION_MAX_CANDIDATES = 64;
740
1263
  var MlsDevGroupValidationError = class extends Error {
741
1264
  static {
742
1265
  __name(this, "MlsDevGroupValidationError");
@@ -747,119 +1270,169 @@ var MlsDevGroupValidationError = class extends Error {
747
1270
  this.name = "MlsDevGroupValidationError";
748
1271
  }
749
1272
  };
750
- var utf83 = new TextEncoder();
751
- function invalid6() {
1273
+ var utf84 = new TextEncoder();
1274
+ function invalid8() {
752
1275
  throw new MlsDevGroupValidationError();
753
1276
  }
754
- __name(invalid6, "invalid");
755
- function boundary5(read) {
1277
+ __name(invalid8, "invalid");
1278
+ function boundary7(read) {
756
1279
  try {
757
1280
  return read();
758
1281
  } catch {
759
- return invalid6();
1282
+ return invalid8();
760
1283
  }
761
1284
  }
762
- __name(boundary5, "boundary");
1285
+ __name(boundary7, "boundary");
763
1286
  function bounded5(value, maximum = MLS_DEV_GROUP_CONTROL_MAX_BYTES) {
764
- if (utf83.encode(JSON.stringify(value)).length > maximum)
765
- invalid6();
1287
+ if (utf84.encode(JSON.stringify(value)).length > maximum)
1288
+ invalid8();
766
1289
  return Object.freeze(value);
767
1290
  }
768
1291
  __name(bounded5, "bounded");
769
- function id3(value) {
1292
+ function id4(value) {
770
1293
  if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..")
771
- invalid6();
1294
+ invalid8();
772
1295
  return value;
773
1296
  }
774
- __name(id3, "id");
775
- function encoded3(value, bytes) {
1297
+ __name(id4, "id");
1298
+ function encoded4(value, bytes) {
776
1299
  decodeCanonicalMlsBase64Url(value, bytes);
777
1300
  return value;
778
1301
  }
779
- __name(encoded3, "encoded");
780
- function boolean2(value) {
1302
+ __name(encoded4, "encoded");
1303
+ function boolean3(value) {
781
1304
  if (typeof value !== "boolean")
782
- invalid6();
1305
+ invalid8();
783
1306
  return value;
784
1307
  }
785
- __name(boolean2, "boolean");
1308
+ __name(boolean3, "boolean");
1309
+ function textProtocol(value) {
1310
+ if (!isMlsDevTextProtocol(value))
1311
+ invalid8();
1312
+ return value;
1313
+ }
1314
+ __name(textProtocol, "textProtocol");
786
1315
  function token(value) {
787
1316
  parseMlsDevCredentialToken(value);
788
1317
  return value;
789
1318
  }
790
1319
  __name(token, "token");
791
- function wire(value) {
1320
+ function wire2(value) {
792
1321
  if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_GROUP_TLS_MAX_BYTES * 4 / 3))
793
- invalid6();
1322
+ invalid8();
794
1323
  const bytes = Math.floor(value.length * 3 / 4);
795
1324
  if (value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value))
796
- invalid6();
1325
+ invalid8();
797
1326
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
798
1327
  if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0)
799
- invalid6();
1328
+ invalid8();
800
1329
  return value;
801
1330
  }
802
- __name(wire, "wire");
803
- function array2(value, maximum) {
1331
+ __name(wire2, "wire");
1332
+ function plaintextJson(value) {
1333
+ 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)
1334
+ invalid8();
1335
+ return value;
1336
+ }
1337
+ __name(plaintextJson, "plaintextJson");
1338
+ function present(value, keys2) {
1339
+ return value && typeof value === "object" ? keys2.filter((key) => Object.hasOwn(value, key)) : [];
1340
+ }
1341
+ __name(present, "present");
1342
+ var pick = /* @__PURE__ */ __name((value, keys2) => Object.fromEntries(keys2.map((key) => [key, value[key]])), "pick");
1343
+ var textExtras = /* @__PURE__ */ __name((text5) => ({ ...text5.replyTo ? { replyTo: text5.replyTo } : {}, ...text5.mentions ? { mentions: text5.mentions } : {} }), "textExtras");
1344
+ function sealedCiphertext(value) {
1345
+ if (typeof value !== "string" || !/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1) invalid8();
1346
+ const bytes = Math.floor(value.length * 3 / 4);
1347
+ if (bytes < 17 || bytes > MLS_DEV_SECRET_ANSWER_MAX_BYTES) invalid8();
1348
+ const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
1349
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid8();
1350
+ return value;
1351
+ }
1352
+ __name(sealedCiphertext, "sealedCiphertext");
1353
+ function array3(value, maximum) {
804
1354
  if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > maximum)
805
- invalid6();
1355
+ invalid8();
806
1356
  const descriptors = Object.getOwnPropertyDescriptors(value);
807
1357
  if (Reflect.ownKeys(descriptors).length !== value.length + 1)
808
- invalid6();
1358
+ invalid8();
809
1359
  return Array.from({ length: value.length }, (_, index) => {
810
1360
  const descriptor = descriptors[index];
811
1361
  if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, "value"))
812
- invalid6();
1362
+ invalid8();
813
1363
  return descriptor.value;
814
1364
  });
815
1365
  }
816
- __name(array2, "array");
1366
+ __name(array3, "array");
817
1367
  function parseMlsDevGroupCreateConversation(value) {
818
- return boundary5(() => {
1368
+ return boundary7(() => {
819
1369
  const input = readMlsDataRecord(value, ["name", "memberIds", "mlsDev"]), config = readMlsDataRecord(input.mlsDev, ["version", "conversationId", "credential"], ["version", "conversationId", "credential", "protocol"]);
820
1370
  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);
1371
+ invalid8();
1372
+ const memberIds = array3(input.memberIds, 31).map((value2) => parseMlsDevEnrollmentPrincipal({ type: "human", id: value2 }).id);
823
1373
  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);
1374
+ invalid8();
1375
+ 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
1376
  });
827
1377
  }
828
1378
  __name(parseMlsDevGroupCreateConversation, "parseMlsDevGroupCreateConversation");
829
1379
  function parseMlsDevGroupHead(value) {
830
- return boundary5(() => {
1380
+ return boundary7(() => {
831
1381
  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) });
1382
+ return Object.freeze({ sequence: requireMlsInteger(input.sequence, 1), epoch: requireMlsInteger(input.epoch), hash: encoded4(input.hash, 32) });
833
1383
  });
834
1384
  }
835
1385
  __name(parseMlsDevGroupHead, "parseMlsDevGroupHead");
836
1386
  function parseMlsDevGroupMarker(value) {
837
- return boundary5(() => {
1387
+ return boundary7(() => {
838
1388
  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) });
1389
+ return Object.freeze({ version: requireMlsLiteral(input.version, 1), groupId: encoded4(input.groupId, 32), head: parseMlsDevGroupHead(input.head) });
840
1390
  });
841
1391
  }
842
1392
  __name(parseMlsDevGroupMarker, "parseMlsDevGroupMarker");
843
1393
  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) });
1394
+ return boundary7(() => {
1395
+ const values = array3(value, MLS_DEV_GROUP_ROSTER_MAX).map((item2) => {
1396
+ const entry = readMlsDataRecord(item2, ["device", "admissionId"]);
1397
+ return Object.freeze({ device: parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: entry.device }).device, admissionId: id4(entry.admissionId) });
848
1398
  });
849
1399
  for (let i = 1; i < values.length; i++)
850
1400
  if (values[i - 1].device.deviceId >= values[i].device.deviceId)
851
- invalid6();
1401
+ invalid8();
852
1402
  return Object.freeze(values);
853
1403
  });
854
1404
  }
855
1405
  __name(parseMlsDevGroupRoster, "parseMlsDevGroupRoster");
1406
+ var MLS_DEV_ROOM_REMOVAL_DEADLINE_MS = 72 * 60 * 60 * 1e3;
1407
+ function parseMlsDevRoomRemoval(value) {
1408
+ return boundary7(() => {
1409
+ const input = readMlsDataRecord(value, ["version", "status", "pending", "closedAtMs"]), devices = /* @__PURE__ */ new Set(), principals = /* @__PURE__ */ new Set();
1410
+ const status = ["pending", "closing", "closed"].includes(input.status) ? input.status : invalid8();
1411
+ const pending = array3(input.pending, MLS_DEV_GROUP_ROSTER_MAX).map((item2) => {
1412
+ const entry = readMlsDataRecord(item2, ["principalId", "deviceIds", "deadlineAtMs"]);
1413
+ const principalId2 = parseMlsDevEnrollmentPrincipal({ type: "human", id: entry.principalId }).id;
1414
+ const deviceIds = array3(entry.deviceIds, MLS_DEV_GROUP_ROSTER_MAX).map(requireMlsUuid);
1415
+ if (principals.has(principalId2)) invalid8();
1416
+ principals.add(principalId2);
1417
+ for (const deviceId of deviceIds) {
1418
+ if (devices.has(deviceId)) invalid8();
1419
+ devices.add(deviceId);
1420
+ }
1421
+ return Object.freeze({ principalId: principalId2, deviceIds: Object.freeze(deviceIds), deadlineAtMs: requireMlsInteger(entry.deadlineAtMs, 1) });
1422
+ });
1423
+ const closedAtMs = input.closedAtMs === null ? null : requireMlsInteger(input.closedAtMs, 1);
1424
+ if (status === "pending" ? !pending.length || closedAtMs !== null : closedAtMs === null || status === "closed" && pending.length) invalid8();
1425
+ return Object.freeze({ version: requireMlsLiteral(input.version, 1), status, pending: Object.freeze(pending), closedAtMs });
1426
+ });
1427
+ }
1428
+ __name(parseMlsDevRoomRemoval, "parseMlsDevRoomRemoval");
856
1429
  function parseMlsDevGroupPreconditions(value) {
857
- return boundary5(() => {
1430
+ return boundary7(() => {
858
1431
  const input = readMlsDataRecord(value, ["membershipRevision", "admissionId", "targetAdmissionId"]);
859
1432
  return Object.freeze({
860
1433
  membershipRevision: requireMlsInteger(input.membershipRevision),
861
- admissionId: id3(input.admissionId),
862
- targetAdmissionId: input.targetAdmissionId === null ? null : id3(input.targetAdmissionId)
1434
+ admissionId: id4(input.admissionId),
1435
+ targetAdmissionId: input.targetAdmissionId === null ? null : id4(input.targetAdmissionId)
863
1436
  });
864
1437
  });
865
1438
  }
@@ -883,37 +1456,40 @@ var unsignedFields = [
883
1456
  ];
884
1457
  function unsigned(input) {
885
1458
  if (typeof input.kind !== "string" || !["create", "add", "remove"].includes(input.kind))
886
- invalid6();
1459
+ invalid8();
887
1460
  const kind = input.kind;
888
1461
  const senderCredential = token(input.senderCredential), sender = parseMlsDevCredentialToken(senderCredential).unsigned.claims.device;
889
1462
  const expectedHead = input.expectedHead === null ? null : parseMlsDevGroupHead(input.expectedHead);
890
1463
  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);
1464
+ const environmentId = requireMlsEnvironmentId(input.environmentId);
1465
+ if (sender.environmentId !== environmentId || roster.some((entry) => entry.device.environmentId !== environmentId))
1466
+ invalid8();
1467
+ const groupInfo = input.groupInfo === null ? null : wire2(input.groupInfo), commit = input.commit === null ? null : wire2(input.commit);
1468
+ const welcome = input.welcome === null ? null : wire2(input.welcome);
893
1469
  const keyPackageClaim = input.keyPackageClaim === null ? null : parseMlsDevKeyPackageClaimReceipt(input.keyPackageClaim);
894
1470
  const removedDeviceId = input.removedDeviceId === null ? null : requireMlsUuid(input.removedDeviceId);
895
1471
  const own = roster.find((entry) => entry.device.deviceId === sender.deviceId);
896
1472
  if (!own || JSON.stringify(own.device) !== JSON.stringify(sender) || own.admissionId !== preconditions.admissionId)
897
- invalid6();
1473
+ invalid8();
898
1474
  if (kind === "create") {
899
1475
  if (expectedHead !== null || epoch !== 0 || roster.length !== 1 || !groupInfo || commit !== null || welcome !== null || keyPackageClaim !== null || removedDeviceId !== null || preconditions.targetAdmissionId !== null)
900
- invalid6();
1476
+ invalid8();
901
1477
  } else {
902
1478
  if (!expectedHead || expectedHead.sequence >= Number.MAX_SAFE_INTEGER || expectedHead.epoch >= Number.MAX_SAFE_INTEGER || epoch !== expectedHead.epoch + 1 || !commit || preconditions.targetAdmissionId === null)
903
- invalid6();
1479
+ invalid8();
904
1480
  if (kind === "add") {
905
1481
  const target = roster.find((entry) => entry.device.deviceId === keyPackageClaim?.recipientDeviceId);
906
1482
  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();
1483
+ invalid8();
908
1484
  } else if (!removedDeviceId || removedDeviceId === sender.deviceId || roster.some((entry) => entry.device.deviceId === removedDeviceId) || welcome !== null || keyPackageClaim !== null)
909
- invalid6();
1485
+ invalid8();
910
1486
  }
911
1487
  return bounded5({
912
1488
  version: requireMlsLiteral(input.version, 1),
913
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
1489
+ environmentId,
914
1490
  kind,
915
- conversationId: id3(input.conversationId),
916
- groupId: encoded3(input.groupId, 32),
1491
+ conversationId: id4(input.conversationId),
1492
+ groupId: encoded4(input.groupId, 32),
917
1493
  senderCredential,
918
1494
  expectedHead,
919
1495
  epoch,
@@ -928,25 +1504,25 @@ function unsigned(input) {
928
1504
  }
929
1505
  __name(unsigned, "unsigned");
930
1506
  function parseMlsDevGroupControl(value) {
931
- return boundary5(() => {
1507
+ return boundary7(() => {
932
1508
  const input = readMlsDataRecord(value, [...unsignedFields, "proof"]);
933
- return bounded5({ ...unsigned(input), proof: encoded3(input.proof, 64) });
1509
+ return bounded5({ ...unsigned(input), proof: encoded4(input.proof, 64) });
934
1510
  });
935
1511
  }
936
1512
  __name(parseMlsDevGroupControl, "parseMlsDevGroupControl");
937
1513
  function parseMlsDevGroupAcceptedControl(value) {
938
- return boundary5(() => {
1514
+ return boundary7(() => {
939
1515
  const input = readMlsDataRecord(value, ["version", "authorization", "operationId", "control", "head", "acceptedAtMs", "membershipRevision"]);
940
1516
  const control = parseMlsDevGroupControl(input.control), head = parseMlsDevGroupHead(input.head);
941
1517
  if (head.sequence !== (control.expectedHead?.sequence ?? 0) + 1 || head.epoch !== control.epoch)
942
- invalid6();
1518
+ invalid8();
943
1519
  const membershipRevision = requireMlsInteger(input.membershipRevision);
944
1520
  if (membershipRevision !== control.preconditions.membershipRevision && !(control.kind === "remove" && membershipRevision === control.preconditions.membershipRevision + 1))
945
- invalid6();
1521
+ invalid8();
946
1522
  return bounded5({
947
1523
  version: requireMlsLiteral(input.version, 1),
948
1524
  authorization: requireMlsLiteral(input.authorization, "group_control_only"),
949
- operationId: id3(input.operationId),
1525
+ operationId: id4(input.operationId),
950
1526
  control,
951
1527
  head,
952
1528
  acceptedAtMs: requireMlsInteger(input.acceptedAtMs),
@@ -955,40 +1531,65 @@ function parseMlsDevGroupAcceptedControl(value) {
955
1531
  });
956
1532
  }
957
1533
  __name(parseMlsDevGroupAcceptedControl, "parseMlsDevGroupAcceptedControl");
1534
+ function parseMlsDevGroupAdmissionsResult(value) {
1535
+ return boundary7(() => {
1536
+ const input = readMlsDataRecord(value, ["version", "conversationId", "membershipRevision", "candidates", "waitingPrincipalIds"]);
1537
+ const candidates = array3(input.candidates, MLS_DEV_GROUP_ADMISSION_MAX_CANDIDATES).map((raw) => {
1538
+ const entry = readMlsDataRecord(raw, ["principal", "deviceId", "targetAdmissionId"]), principal2 = readMlsDataRecord(entry.principal, ["type", "id"]);
1539
+ if (principal2.type !== "human" && principal2.type !== "ai_agent") invalid8();
1540
+ return Object.freeze({
1541
+ principal: Object.freeze({ type: principal2.type, id: id4(principal2.id) }),
1542
+ deviceId: requireMlsUuid(entry.deviceId),
1543
+ targetAdmissionId: id4(entry.targetAdmissionId)
1544
+ });
1545
+ });
1546
+ if (new Set(candidates.map((entry) => entry.deviceId)).size !== candidates.length) invalid8();
1547
+ const waiting = array3(input.waitingPrincipalIds, 32).map(id4);
1548
+ if (new Set(waiting).size !== waiting.length) invalid8();
1549
+ return bounded5(Object.freeze({
1550
+ version: requireMlsLiteral(input.version, 1),
1551
+ conversationId: id4(input.conversationId),
1552
+ membershipRevision: requireMlsInteger(input.membershipRevision, 1),
1553
+ candidates: Object.freeze(candidates),
1554
+ waitingPrincipalIds: Object.freeze(waiting)
1555
+ }), 64 * 1024);
1556
+ });
1557
+ }
1558
+ __name(parseMlsDevGroupAdmissionsResult, "parseMlsDevGroupAdmissionsResult");
958
1559
  function parseMlsDevGroupQuery(value) {
959
- return boundary5(() => {
1560
+ return boundary7(() => {
960
1561
  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();
1562
+ const limit2 = requireMlsInteger(input.limit, 1);
1563
+ if (limit2 > MLS_DEV_GROUP_QUERY_MAX_CONTROLS)
1564
+ invalid8();
964
1565
  return bounded5({
965
1566
  version: requireMlsLiteral(input.version, 1),
966
- conversationId: id3(input.conversationId),
1567
+ conversationId: id4(input.conversationId),
967
1568
  credential: token(input.credential),
968
1569
  afterSequence: requireMlsInteger(input.afterSequence),
969
- limit
1570
+ limit: limit2
970
1571
  }, 16 * 1024);
971
1572
  });
972
1573
  }
973
1574
  __name(parseMlsDevGroupQuery, "parseMlsDevGroupQuery");
974
1575
  function parseMlsDevGroupQueryResult(value) {
975
- return boundary5(() => {
1576
+ return boundary7(() => {
976
1577
  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);
1578
+ const conversationId = id4(input.conversationId), marker = input.marker === null ? null : parseMlsDevGroupMarker(input.marker);
1579
+ const controls = array3(input.controls, MLS_DEV_GROUP_QUERY_MAX_CONTROLS).map(parseMlsDevGroupAcceptedControl);
1580
+ const nextSequence = requireMlsInteger(input.nextSequence), terminal = boolean3(input.terminal), hasMore = boolean3(input.hasMore);
980
1581
  for (let i = 0; i < controls.length; i++) {
981
1582
  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();
1583
+ invalid8();
983
1584
  }
984
1585
  if (controls.length && controls.at(-1).head.sequence !== nextSequence || marker && nextSequence > marker.head.sequence || !marker && (controls.length || nextSequence || terminal || hasMore))
985
- invalid6();
1586
+ invalid8();
986
1587
  return bounded5({
987
1588
  version: requireMlsLiteral(input.version, 1),
988
1589
  conversationId,
989
1590
  marker,
990
1591
  membershipRevision: requireMlsInteger(input.membershipRevision),
991
- admissionId: id3(input.admissionId),
1592
+ admissionId: id4(input.admissionId),
992
1593
  roster: parseMlsDevGroupRoster(input.roster),
993
1594
  controls: Object.freeze(controls),
994
1595
  nextSequence,
@@ -999,42 +1600,43 @@ function parseMlsDevGroupQueryResult(value) {
999
1600
  }
1000
1601
  __name(parseMlsDevGroupQueryResult, "parseMlsDevGroupQueryResult");
1001
1602
  function parseMlsDevGroupContext(value) {
1002
- return boundary5(() => {
1603
+ return boundary7(() => {
1003
1604
  const input = readMlsDataRecord(value, ["version", "environmentId", "conversationId", "groupId", "deviceId", "installationId", "revision"], ["version", "environmentId", "conversationId", "groupId", "deviceId", "installationId", "revision", "protocol"]);
1004
1605
  const revision2 = requireMlsInteger(input.revision);
1005
1606
  if (revision2 >= Number.MAX_SAFE_INTEGER)
1006
- invalid6();
1607
+ invalid8();
1007
1608
  return Object.freeze({
1008
1609
  version: requireMlsLiteral(input.version, 1),
1009
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
1010
- conversationId: id3(input.conversationId),
1011
- groupId: encoded3(input.groupId, 32),
1610
+ environmentId: requireMlsEnvironmentId(input.environmentId),
1611
+ conversationId: id4(input.conversationId),
1612
+ groupId: encoded4(input.groupId, 32),
1012
1613
  deviceId: requireMlsUuid(input.deviceId),
1013
1614
  installationId: parseMlsDevInstallationId(input.installationId),
1014
1615
  revision: revision2,
1015
- ...Object.hasOwn(input, "protocol") ? { protocol: requireMlsLiteral(input.protocol, MLS_DEV_TEXT_PROTOCOL) } : {}
1616
+ ...Object.hasOwn(input, "protocol") ? { protocol: textProtocol(input.protocol) } : {}
1016
1617
  });
1017
1618
  });
1018
1619
  }
1019
1620
  __name(parseMlsDevGroupContext, "parseMlsDevGroupContext");
1020
1621
  function parseMlsDevGroupCommand(value) {
1021
- return boundary5(() => {
1622
+ return boundary7(() => {
1022
1623
  if (!value || typeof value !== "object")
1023
- invalid6();
1624
+ invalid8();
1024
1625
  const descriptor = Object.getOwnPropertyDescriptor(value, "op");
1025
1626
  if (!descriptor || !Object.hasOwn(descriptor, "value"))
1026
- invalid6();
1627
+ invalid8();
1027
1628
  const op = descriptor.value;
1028
1629
  if (op === "process_application") {
1029
1630
  const input2 = readMlsDataRecord(value, ["op", "entry"]), entry = parseMlsDevGroupFeedEntry(input2.entry);
1030
- if (entry.kind !== "application")
1031
- invalid6();
1631
+ if (entry.kind !== "application" || !entry.receiptProof)
1632
+ invalid8();
1032
1633
  return bounded5({ op, entry });
1033
1634
  }
1034
1635
  if (op === "encrypt_text") {
1035
- const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "text"]);
1636
+ const extras = present(value, ["replyTo", "mentions"]);
1637
+ const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "text", ...extras]);
1036
1638
  const credential = token(input2.credential), senderDeviceId = parseMlsDevCredentialToken(credential).unsigned.claims.device.deviceId;
1037
- const text3 = parseMlsDevTextPayload({
1639
+ const text5 = parseMlsDevTextPayload({
1038
1640
  version: 1,
1039
1641
  kind: "text",
1040
1642
  conversationId: "validation",
@@ -1042,117 +1644,283 @@ function parseMlsDevGroupCommand(value) {
1042
1644
  messageId: input2.messageId,
1043
1645
  operationId: input2.operationId,
1044
1646
  senderDeviceId,
1045
- text: input2.text
1647
+ text: input2.text,
1648
+ ...pick(input2, extras)
1046
1649
  });
1047
1650
  return bounded5({
1048
1651
  op,
1049
- operationId: text3.operationId,
1050
- messageId: text3.messageId,
1652
+ operationId: text5.operationId,
1653
+ messageId: text5.messageId,
1051
1654
  credential,
1052
1655
  expectedHead: parseMlsDevGroupHead(input2.expectedHead),
1053
1656
  preconditions: parseMlsDevApplicationPreconditions(input2.preconditions),
1054
- text: text3.text
1657
+ text: text5.text,
1658
+ ...textExtras(text5)
1659
+ });
1660
+ }
1661
+ if (op === "encrypt_item") {
1662
+ const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "item"]);
1663
+ const credential = token(input2.credential), senderDeviceId = parseMlsDevCredentialToken(credential).unsigned.claims.device.deviceId;
1664
+ const parsed = parseMlsDevItemPayload({
1665
+ version: 1,
1666
+ kind: "item",
1667
+ conversationId: "validation",
1668
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1669
+ messageId: input2.messageId,
1670
+ operationId: input2.operationId,
1671
+ senderDeviceId,
1672
+ item: input2.item
1673
+ });
1674
+ return bounded5({
1675
+ op,
1676
+ operationId: parsed.operationId,
1677
+ messageId: parsed.messageId,
1678
+ credential,
1679
+ expectedHead: parseMlsDevGroupHead(input2.expectedHead),
1680
+ preconditions: parseMlsDevApplicationPreconditions(input2.preconditions),
1681
+ item: parsed.item
1682
+ });
1683
+ }
1684
+ if (op === "encrypt_interaction") {
1685
+ const input2 = readMlsDataRecord(value, ["op", "operationId", "messageId", "credential", "expectedHead", "preconditions", "interaction", "body", "seal"]);
1686
+ const credential = token(input2.credential), interaction = parseMlsDevInteractionBinding(input2.interaction);
1687
+ const body = readMlsDataRecord(input2.body, Reflect.ownKeys(input2.body ?? {}).filter((key) => typeof key === "string"));
1688
+ let seal = null;
1689
+ if (interaction.role === "request") {
1690
+ if (Object.hasOwn(body, "secretKey") || input2.seal !== null)
1691
+ invalid8();
1692
+ const parsed = parseMlsDevInteractionRequestBody(interaction.kind === "secret" ? { ...body, secretKey: { kem: "x25519", publicKey: "A".repeat(43) } } : body);
1693
+ if (parsed.requestId !== interaction.requestId || parsed.kind !== interaction.kind || parsed.expiresAtMs !== interaction.expiresAtMs || parsed.responderIds[0] !== interaction.responderIds[0])
1694
+ invalid8();
1695
+ } else if (interaction.role === "response") {
1696
+ if (input2.seal === null) {
1697
+ const parsed = parseMlsDevInteractionResponseBody(body);
1698
+ if (parsed.requestId !== interaction.requestId || parsed.agentId !== interaction.agentId || "sealed" in parsed.answer)
1699
+ invalid8();
1700
+ } else {
1701
+ const fields3 = readMlsDataRecord(input2.seal, ["text", "publicKey", "requesterDeviceId"]), ids2 = readMlsDataRecord(body, ["requestId", "agentId"]);
1702
+ 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)
1703
+ invalid8();
1704
+ seal = Object.freeze({ text: fields3.text, publicKey: encoded4(fields3.publicKey, 32), requesterDeviceId: requireMlsUuid(fields3.requesterDeviceId) });
1705
+ }
1706
+ } else if (input2.seal !== null || parseMlsDevInteractionWithdrawBody(body).requestId !== interaction.requestId)
1707
+ invalid8();
1708
+ const ids = parseMlsDevTextPayload({
1709
+ version: 1,
1710
+ kind: "text",
1711
+ conversationId: "validation",
1712
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1713
+ messageId: input2.messageId,
1714
+ operationId: input2.operationId,
1715
+ senderDeviceId: parseMlsDevCredentialToken(credential).unsigned.claims.device.deviceId,
1716
+ text: "x"
1717
+ });
1718
+ if (utf84.encode(JSON.stringify(body)).length > MLS_DEV_TEXT_MAX_BYTES)
1719
+ invalid8();
1720
+ return bounded5({
1721
+ op,
1722
+ operationId: ids.operationId,
1723
+ messageId: ids.messageId,
1724
+ credential,
1725
+ expectedHead: parseMlsDevGroupHead(input2.expectedHead),
1726
+ preconditions: parseMlsDevApplicationPreconditions(input2.preconditions),
1727
+ interaction,
1728
+ body: Object.freeze(body),
1729
+ seal
1730
+ });
1731
+ }
1732
+ if (op === "open_secret_answer") {
1733
+ const input2 = readMlsDataRecord(value, ["op", "requestId", "responderId", "responderDeviceId", "sealed"]), sealed = readMlsDataRecord(input2.sealed, ["enc", "ciphertext"]);
1734
+ const binding3 = parseMlsDevInteractionBinding({ role: "response", requestId: input2.requestId, agentId: input2.responderId });
1735
+ return bounded5({
1736
+ op,
1737
+ requestId: binding3.requestId,
1738
+ responderId: id4(input2.responderId),
1739
+ responderDeviceId: requireMlsUuid(input2.responderDeviceId),
1740
+ sealed: Object.freeze({ enc: encoded4(sealed.enc, 32), ciphertext: sealedCiphertext(sealed.ciphertext) })
1055
1741
  });
1056
1742
  }
1057
1743
  if (op === "discard") {
1058
1744
  const input2 = readMlsDataRecord(value, ["op", "operationId", "control"]);
1059
- return bounded5({ op, operationId: id3(input2.operationId), control: parseMlsDevGroupControl(input2.control) });
1745
+ return bounded5({ op, operationId: id4(input2.operationId), control: parseMlsDevGroupControl(input2.control) });
1060
1746
  }
1061
1747
  if (op === "finalize") {
1062
1748
  const input2 = readMlsDataRecord(value, ["op", "accepted"]);
1063
1749
  return bounded5({ op, accepted: parseMlsDevGroupAcceptedControl(input2.accepted) });
1064
1750
  }
1065
1751
  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) };
1752
+ const input2 = readMlsDataRecord(value, op === "join" ? ["op", "credential", "accepted", "receiptProof", "feedOrdinal", "keyPackageId"] : ["op", "credential", "accepted", "receiptProof", "feedOrdinal"]);
1753
+ const common2 = {
1754
+ credential: token(input2.credential),
1755
+ accepted: parseMlsDevGroupAcceptedControl(input2.accepted),
1756
+ receiptProof: parseMlsDevFeedReceiptProof(input2.receiptProof),
1757
+ feedOrdinal: requireMlsInteger(input2.feedOrdinal, 1)
1758
+ };
1068
1759
  if (op === "join") {
1069
1760
  if (common2.accepted.control.kind !== "add")
1070
- invalid6();
1761
+ invalid8();
1071
1762
  return bounded5({ op, ...common2, keyPackageId: requireMlsUuid(input2.keyPackageId) });
1072
1763
  }
1073
1764
  return bounded5({ op, ...common2 });
1074
1765
  }
1075
1766
  const common = ["op", "operationId", "credential", "preconditions"];
1076
1767
  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) };
1768
+ const fields2 = { operationId: id4(input.operationId), credential: token(input.credential), preconditions: parseMlsDevGroupPreconditions(input.preconditions) };
1078
1769
  if (op === "create") {
1079
- if (fields.preconditions.targetAdmissionId !== null)
1080
- invalid6();
1081
- return bounded5({ op, ...fields });
1770
+ if (fields2.preconditions.targetAdmissionId !== null)
1771
+ invalid8();
1772
+ return bounded5({ op, ...fields2 });
1082
1773
  }
1083
- if (fields.preconditions.targetAdmissionId === null)
1084
- invalid6();
1774
+ if (fields2.preconditions.targetAdmissionId === null)
1775
+ invalid8();
1085
1776
  const expectedHead = parseMlsDevGroupHead(input.expectedHead);
1086
1777
  if (op === "add")
1087
1778
  return bounded5({
1088
1779
  op,
1089
- ...fields,
1780
+ ...fields2,
1090
1781
  expectedHead,
1091
1782
  keyPackageClaim: parseMlsDevKeyPackageClaimReceipt(input.keyPackageClaim)
1092
1783
  });
1093
1784
  if (op === "remove")
1094
1785
  return bounded5({
1095
1786
  op,
1096
- ...fields,
1787
+ ...fields2,
1097
1788
  expectedHead,
1098
1789
  removedDeviceId: requireMlsUuid(input.removedDeviceId)
1099
1790
  });
1100
- return invalid6();
1791
+ return invalid8();
1101
1792
  });
1102
1793
  }
1103
1794
  __name(parseMlsDevGroupCommand, "parseMlsDevGroupCommand");
1104
1795
  function parseMlsDevGroupPreparation(value) {
1105
- return boundary5(() => {
1796
+ return boundary7(() => {
1106
1797
  const input = readMlsDataRecord(value, ["wrappedState", "payload"]);
1107
1798
  if (typeof input.wrappedState !== "string" || input.wrappedState.length > MLS_DEV_GROUP_WRAPPED_MAX_BYTES || !input.wrappedState.startsWith("v1:"))
1108
- invalid6();
1799
+ invalid8();
1109
1800
  const body = input.wrappedState.slice(3);
1110
1801
  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();
1802
+ invalid8();
1112
1803
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1113
1804
  if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0 || !body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0)
1114
- invalid6();
1805
+ invalid8();
1115
1806
  const kind = Object.getOwnPropertyDescriptor(input.payload ?? {}, "kind");
1116
1807
  if (!kind || !Object.hasOwn(kind, "value"))
1117
- invalid6();
1808
+ invalid8();
1118
1809
  let payload;
1119
1810
  if (kind.value === "application") {
1120
- const fields = readMlsDataRecord(input.payload, ["kind", "envelope"]);
1121
- payload = Object.freeze({ kind: "application", envelope: parseMlsDevApplicationEnvelope(fields.envelope) });
1811
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "envelope", ...present(input.payload, ["payload"])]);
1812
+ payload = Object.freeze({
1813
+ kind: "application",
1814
+ envelope: parseMlsDevApplicationEnvelope(fields2.envelope),
1815
+ ...fields2.payload === void 0 ? {} : { payload: plaintextJson(fields2.payload) }
1816
+ });
1817
+ } else if (kind.value === "item") {
1818
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "payload", "feedOrdinal"]);
1819
+ const ids = parseMlsDevTextPayload({
1820
+ version: 1,
1821
+ kind: "text",
1822
+ conversationId: "validation",
1823
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1824
+ messageId: fields2.messageId,
1825
+ operationId: fields2.operationId,
1826
+ senderDeviceId: fields2.senderDeviceId,
1827
+ text: "x"
1828
+ });
1829
+ payload = Object.freeze({
1830
+ kind: "item",
1831
+ messageId: ids.messageId,
1832
+ operationId: ids.operationId,
1833
+ senderDeviceId: ids.senderDeviceId,
1834
+ payload: plaintextJson(fields2.payload),
1835
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1836
+ });
1122
1837
  } else if (kind.value === "text") {
1123
- const fields = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "text", "feedOrdinal"]);
1124
- const text3 = parseMlsDevTextPayload({
1838
+ const extras = present(input.payload, ["replyTo", "mentions"]);
1839
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "text", "feedOrdinal", ...extras]);
1840
+ const text5 = parseMlsDevTextPayload({
1125
1841
  version: 1,
1126
1842
  kind: "text",
1127
1843
  conversationId: "validation",
1128
1844
  groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1129
- messageId: fields.messageId,
1130
- operationId: fields.operationId,
1131
- senderDeviceId: fields.senderDeviceId,
1132
- text: fields.text
1845
+ messageId: fields2.messageId,
1846
+ operationId: fields2.operationId,
1847
+ senderDeviceId: fields2.senderDeviceId,
1848
+ text: fields2.text,
1849
+ ...pick(fields2, extras)
1133
1850
  });
1134
1851
  payload = Object.freeze({
1135
1852
  kind: "text",
1136
- messageId: text3.messageId,
1137
- operationId: text3.operationId,
1138
- senderDeviceId: text3.senderDeviceId,
1139
- text: text3.text,
1140
- feedOrdinal: requireMlsInteger(fields.feedOrdinal, 1)
1853
+ messageId: text5.messageId,
1854
+ operationId: text5.operationId,
1855
+ senderDeviceId: text5.senderDeviceId,
1856
+ text: text5.text,
1857
+ ...textExtras(text5),
1858
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1859
+ });
1860
+ } else if (kind.value === "interaction_application") {
1861
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "envelope", "payload"]);
1862
+ payload = Object.freeze({ kind: "interaction_application", envelope: parseMlsDevApplicationEnvelope(fields2.envelope), payload: plaintextJson(fields2.payload) });
1863
+ if (!payload.envelope.interaction)
1864
+ invalid8();
1865
+ } else if (kind.value === "interaction") {
1866
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "payload", "feedOrdinal"]);
1867
+ const ids = parseMlsDevTextPayload({
1868
+ version: 1,
1869
+ kind: "text",
1870
+ conversationId: "validation",
1871
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1872
+ messageId: fields2.messageId,
1873
+ operationId: fields2.operationId,
1874
+ senderDeviceId: fields2.senderDeviceId,
1875
+ text: "x"
1876
+ });
1877
+ payload = Object.freeze({
1878
+ kind: "interaction",
1879
+ messageId: ids.messageId,
1880
+ operationId: ids.operationId,
1881
+ senderDeviceId: ids.senderDeviceId,
1882
+ payload: plaintextJson(fields2.payload),
1883
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1141
1884
  });
1885
+ } else if (kind.value === "invalid") {
1886
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "messageId", "operationId", "senderDeviceId", "feedOrdinal"]);
1887
+ const ids = parseMlsDevTextPayload({
1888
+ version: 1,
1889
+ kind: "text",
1890
+ conversationId: "validation",
1891
+ groupId: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1892
+ messageId: fields2.messageId,
1893
+ operationId: fields2.operationId,
1894
+ senderDeviceId: fields2.senderDeviceId,
1895
+ text: "x"
1896
+ });
1897
+ payload = Object.freeze({
1898
+ kind: "invalid",
1899
+ messageId: ids.messageId,
1900
+ operationId: ids.operationId,
1901
+ senderDeviceId: ids.senderDeviceId,
1902
+ feedOrdinal: requireMlsInteger(fields2.feedOrdinal, 1)
1903
+ });
1904
+ } else if (kind.value === "secret") {
1905
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "requestId", "text"]);
1906
+ const binding3 = parseMlsDevInteractionBinding({ role: "withdraw", requestId: fields2.requestId });
1907
+ 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)
1908
+ invalid8();
1909
+ payload = Object.freeze({ kind: "secret", requestId: binding3.requestId, text: fields2.text });
1142
1910
  } else if (kind.value === "control") {
1143
- const fields = readMlsDataRecord(input.payload, ["kind", "control"]);
1144
- payload = Object.freeze({ kind: "control", control: parseMlsDevGroupControl(fields.control) });
1911
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "control"]);
1912
+ payload = Object.freeze({ kind: "control", control: parseMlsDevGroupControl(fields2.control) });
1145
1913
  } 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) });
1914
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "operationId", "head"]);
1915
+ payload = Object.freeze({ kind: "discarded", operationId: id4(fields2.operationId), head: fields2.head === null ? null : parseMlsDevGroupHead(fields2.head) });
1148
1916
  } else {
1149
- const fields = readMlsDataRecord(input.payload, ["kind", "head", "roster", "removed", "consumedKeyPackageId"]);
1917
+ const fields2 = readMlsDataRecord(input.payload, ["kind", "head", "roster", "removed", "consumedKeyPackageId"]);
1150
1918
  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)
1919
+ kind: requireMlsLiteral(fields2.kind, "applied"),
1920
+ head: parseMlsDevGroupHead(fields2.head),
1921
+ roster: parseMlsDevGroupRoster(fields2.roster),
1922
+ removed: boolean3(fields2.removed),
1923
+ consumedKeyPackageId: fields2.consumedKeyPackageId === null ? null : requireMlsUuid(fields2.consumedKeyPackageId)
1156
1924
  });
1157
1925
  }
1158
1926
  return bounded5({ wrappedState: input.wrappedState, payload }, MLS_DEV_GROUP_PREPARATION_MAX_BYTES);
@@ -1162,9 +1930,25 @@ __name(parseMlsDevGroupPreparation, "parseMlsDevGroupPreparation");
1162
1930
 
1163
1931
  // ../backend-contracts/src/mlsDevApplication.ts
1164
1932
  var MLS_DEV_TEXT_PROTOCOL = "canon.mls.dev-text.v1";
1933
+ var MLS_DEV_TEXT_PROTOCOL_V2 = "canon.mls.dev-text.v2";
1934
+ var MLS_DEV_TEXT_PROTOCOL_V3 = "canon.mls.dev-text.v3";
1935
+ var MLS_DEV_TEXT_PROTOCOLS = [MLS_DEV_TEXT_PROTOCOL, MLS_DEV_TEXT_PROTOCOL_V2, MLS_DEV_TEXT_PROTOCOL_V3];
1936
+ function isMlsDevTextProtocol(value) {
1937
+ return MLS_DEV_TEXT_PROTOCOLS.some((protocol) => protocol === value);
1938
+ }
1939
+ __name(isMlsDevTextProtocol, "isMlsDevTextProtocol");
1940
+ function mlsDevProtocolCarriesCards(value) {
1941
+ return value === MLS_DEV_TEXT_PROTOCOL_V2 || value === MLS_DEV_TEXT_PROTOCOL_V3;
1942
+ }
1943
+ __name(mlsDevProtocolCarriesCards, "mlsDevProtocolCarriesCards");
1944
+ var MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS = 1024;
1945
+ var MLS_DEV_MENTIONS_MAX = 32;
1946
+ var MLS_DEV_INTERACTION_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,160}$/;
1947
+ var MLS_DEV_INTERACTION_KINDS = ["approval", "question", "secret"];
1165
1948
  var MLS_DEV_APPLICATION_TLS_MAX_BYTES = 256 * 1024;
1166
1949
  var MLS_DEV_APPLICATION_MAX_BYTES = 384 * 1024;
1167
1950
  var MLS_DEV_TEXT_MAX_BYTES = 32 * 1024;
1951
+ var MLS_DEV_ITEM_TYPES = ["image", "video", "audio", "file"];
1168
1952
  var MlsDevApplicationValidationError = class extends Error {
1169
1953
  static {
1170
1954
  __name(this, "MlsDevApplicationValidationError");
@@ -1174,125 +1958,245 @@ var MlsDevApplicationValidationError = class extends Error {
1174
1958
  super("INVALID_MLS_DEV_APPLICATION");
1175
1959
  this.name = "MlsDevApplicationValidationError";
1176
1960
  }
1177
- };
1178
- var utf84 = new TextEncoder();
1179
- function invalid7() {
1961
+ };
1962
+ var utf85 = new TextEncoder();
1963
+ function invalid9() {
1180
1964
  throw new MlsDevApplicationValidationError();
1181
1965
  }
1182
- __name(invalid7, "invalid");
1183
- function boundary6(read) {
1966
+ __name(invalid9, "invalid");
1967
+ function boundary8(read) {
1184
1968
  try {
1185
1969
  return read();
1186
1970
  } catch {
1187
- return invalid7();
1971
+ return invalid9();
1188
1972
  }
1189
1973
  }
1190
- __name(boundary6, "boundary");
1974
+ __name(boundary8, "boundary");
1191
1975
  function bounded6(value) {
1192
- if (utf84.encode(JSON.stringify(value)).length > MLS_DEV_APPLICATION_MAX_BYTES)
1193
- invalid7();
1976
+ if (utf85.encode(JSON.stringify(value)).length > MLS_DEV_APPLICATION_MAX_BYTES)
1977
+ invalid9();
1194
1978
  return Object.freeze(value);
1195
1979
  }
1196
1980
  __name(bounded6, "bounded");
1197
- function id4(value) {
1981
+ function id5(value) {
1198
1982
  if (typeof value !== "string" || !/^[A-Za-z0-9_.:~-]{1,200}$/.test(value) || value === "." || value === "..")
1199
- invalid7();
1983
+ invalid9();
1200
1984
  return value;
1201
1985
  }
1202
- __name(id4, "id");
1986
+ __name(id5, "id");
1987
+ function isMlsDevMessageId(value) {
1988
+ return typeof value === "string" && /^[A-Za-z0-9_.:~-]{1,200}$/.test(value) && value !== "." && value !== ".." && !value.startsWith("membership-");
1989
+ }
1990
+ __name(isMlsDevMessageId, "isMlsDevMessageId");
1203
1991
  function messageId(value) {
1204
- const result = id4(value);
1205
- if (result.startsWith("membership-"))
1206
- invalid7();
1207
- return result;
1992
+ if (!isMlsDevMessageId(value))
1993
+ invalid9();
1994
+ return value;
1208
1995
  }
1209
1996
  __name(messageId, "messageId");
1210
- function encoded4(value, bytes) {
1997
+ function interactionId2(value) {
1998
+ if (typeof value !== "string" || !MLS_DEV_INTERACTION_ID_PATTERN.test(value) || value === "." || value === "..")
1999
+ invalid9();
2000
+ return value;
2001
+ }
2002
+ __name(interactionId2, "interactionId");
2003
+ function parseMlsDevInteractionBinding(value) {
2004
+ return boundary8(() => {
2005
+ const role = value && typeof value === "object" ? Object.getOwnPropertyDescriptor(value, "role") : void 0;
2006
+ if (!role || !Object.hasOwn(role, "value"))
2007
+ invalid9();
2008
+ if (role.value === "request") {
2009
+ const input2 = readMlsDataRecord(value, ["role", "requestId", "kind", "responderIds", "expiresAtMs"]);
2010
+ if (typeof input2.kind !== "string" || !MLS_DEV_INTERACTION_KINDS.includes(input2.kind))
2011
+ invalid9();
2012
+ const responders = input2.responderIds;
2013
+ if (!Array.isArray(responders) || Object.getPrototypeOf(responders) !== Array.prototype || responders.length !== 1 || Reflect.ownKeys(Object.getOwnPropertyDescriptors(responders)).length !== 2)
2014
+ invalid9();
2015
+ const only = Object.getOwnPropertyDescriptor(responders, 0);
2016
+ if (!only || !only.enumerable || !Object.hasOwn(only, "value"))
2017
+ invalid9();
2018
+ const expiresAtMs = requireMlsInteger(input2.expiresAtMs, 1);
2019
+ return Object.freeze({
2020
+ role: "request",
2021
+ requestId: interactionId2(input2.requestId),
2022
+ kind: input2.kind,
2023
+ responderIds: Object.freeze([id5(only.value)]),
2024
+ expiresAtMs
2025
+ });
2026
+ }
2027
+ if (role.value === "response") {
2028
+ const input2 = readMlsDataRecord(value, ["role", "requestId", "agentId"]);
2029
+ return Object.freeze({ role: "response", requestId: interactionId2(input2.requestId), agentId: id5(input2.agentId) });
2030
+ }
2031
+ const input = readMlsDataRecord(value, ["role", "requestId"]);
2032
+ return Object.freeze({ role: requireMlsLiteral(input.role, "withdraw"), requestId: interactionId2(input.requestId) });
2033
+ });
2034
+ }
2035
+ __name(parseMlsDevInteractionBinding, "parseMlsDevInteractionBinding");
2036
+ function encoded5(value, bytes) {
1211
2037
  decodeCanonicalMlsBase64Url(value, bytes);
1212
2038
  return value;
1213
2039
  }
1214
- __name(encoded4, "encoded");
2040
+ __name(encoded5, "encoded");
1215
2041
  function parseMlsDevApplicationWire(value) {
1216
- return boundary6(() => {
2042
+ return boundary8(() => {
1217
2043
  if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_APPLICATION_TLS_MAX_BYTES * 4 / 3))
1218
- invalid7();
2044
+ invalid9();
1219
2045
  const bytes = Math.floor(value.length * 3 / 4);
1220
2046
  if (bytes > MLS_DEV_APPLICATION_TLS_MAX_BYTES || value.length !== Math.ceil(bytes * 4 / 3) || !/^[A-Za-z0-9_-]+$/.test(value))
1221
- invalid7();
2047
+ invalid9();
1222
2048
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
1223
2049
  if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0)
1224
- invalid7();
2050
+ invalid9();
1225
2051
  return value;
1226
2052
  });
1227
2053
  }
1228
2054
  __name(parseMlsDevApplicationWire, "parseMlsDevApplicationWire");
1229
2055
  function parseMlsDevApplicationPreconditions(value) {
1230
- return boundary6(() => {
2056
+ return boundary8(() => {
1231
2057
  const input = readMlsDataRecord(value, ["membershipRevision", "admissionId"]);
1232
- return Object.freeze({ membershipRevision: requireMlsInteger(input.membershipRevision), admissionId: id4(input.admissionId) });
2058
+ return Object.freeze({ membershipRevision: requireMlsInteger(input.membershipRevision), admissionId: id5(input.admissionId) });
1233
2059
  });
1234
2060
  }
1235
2061
  __name(parseMlsDevApplicationPreconditions, "parseMlsDevApplicationPreconditions");
1236
2062
  var bindingFields = ["version", "environmentId", "conversationId", "groupId", "messageId", "senderCredential", "expectedHead", "preconditions"];
2063
+ var interactionBindingFields = [...bindingFields, "interaction"];
1237
2064
  function binding(input) {
1238
- parseMlsDevCredentialToken(input.senderCredential);
2065
+ const environmentId = requireMlsEnvironmentId(input.environmentId);
2066
+ if (parseMlsDevCredentialToken(input.senderCredential).unsigned.claims.device.environmentId !== environmentId) invalid9();
1239
2067
  return {
1240
2068
  version: requireMlsLiteral(input.version, 1),
1241
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
1242
- conversationId: id4(input.conversationId),
1243
- groupId: encoded4(input.groupId, 32),
2069
+ environmentId,
2070
+ conversationId: id5(input.conversationId),
2071
+ groupId: encoded5(input.groupId, 32),
1244
2072
  messageId: messageId(input.messageId),
1245
2073
  senderCredential: input.senderCredential,
1246
2074
  expectedHead: parseMlsDevGroupHead(input.expectedHead),
1247
- preconditions: parseMlsDevApplicationPreconditions(input.preconditions)
2075
+ preconditions: parseMlsDevApplicationPreconditions(input.preconditions),
2076
+ ...Object.hasOwn(input, "interaction") ? { interaction: parseMlsDevInteractionBinding(input.interaction) } : {}
1248
2077
  };
1249
2078
  }
1250
2079
  __name(binding, "binding");
2080
+ function fields(value, extra) {
2081
+ return readMlsDataRecord(value, [...bindingFields, ...extra], [...interactionBindingFields, ...extra]);
2082
+ }
2083
+ __name(fields, "fields");
1251
2084
  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) });
2085
+ return boundary8(() => {
2086
+ const input = fields(value, ["ciphertext", "proof"]);
2087
+ return bounded6({ ...binding(input), ciphertext: parseMlsDevApplicationWire(input.ciphertext), proof: encoded5(input.proof, 64) });
1255
2088
  });
1256
2089
  }
1257
2090
  __name(parseMlsDevApplicationEnvelope, "parseMlsDevApplicationEnvelope");
1258
2091
  function parseMlsDevApplicationReceipt(value) {
1259
- return boundary6(() => {
2092
+ return boundary8(() => {
1260
2093
  const input = readMlsDataRecord(value, ["version", "authorization", "operationId", "conversationId", "groupId", "messageId", "feedOrdinal", "head", "acceptedAtMs", "envelopeHash"]);
1261
2094
  return bounded6({
1262
2095
  version: requireMlsLiteral(input.version, 1),
1263
2096
  authorization: requireMlsLiteral(input.authorization, "encrypted_text_only"),
1264
- operationId: id4(input.operationId),
1265
- conversationId: id4(input.conversationId),
1266
- groupId: encoded4(input.groupId, 32),
2097
+ operationId: id5(input.operationId),
2098
+ conversationId: id5(input.conversationId),
2099
+ groupId: encoded5(input.groupId, 32),
1267
2100
  messageId: messageId(input.messageId),
1268
2101
  feedOrdinal: requireMlsInteger(input.feedOrdinal, 1),
1269
2102
  head: parseMlsDevGroupHead(input.head),
1270
2103
  acceptedAtMs: requireMlsInteger(input.acceptedAtMs),
1271
- envelopeHash: encoded4(input.envelopeHash, 32)
2104
+ envelopeHash: encoded5(input.envelopeHash, 32)
1272
2105
  });
1273
2106
  });
1274
2107
  }
1275
2108
  __name(parseMlsDevApplicationReceipt, "parseMlsDevApplicationReceipt");
2109
+ function text2(value) {
2110
+ 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)
2111
+ invalid9();
2112
+ return value;
2113
+ }
2114
+ __name(text2, "text");
2115
+ function textExtras2(value) {
2116
+ const extras = {};
2117
+ if (Object.hasOwn(value, "replyTo")) {
2118
+ const reply = readMlsDataRecord(value.replyTo, ["messageId", "quote"]);
2119
+ if ([...text2(reply.quote)].length > MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS)
2120
+ invalid9();
2121
+ extras.replyTo = Object.freeze({ messageId: messageId(reply.messageId), quote: reply.quote });
2122
+ }
2123
+ if (Object.hasOwn(value, "mentions")) {
2124
+ const mentions = value.mentions;
2125
+ if (!Array.isArray(mentions) || mentions.length < 1 || mentions.length > MLS_DEV_MENTIONS_MAX || new Set(mentions).size !== mentions.length)
2126
+ invalid9();
2127
+ extras.mentions = Object.freeze(mentions.map(id5));
2128
+ }
2129
+ return extras;
2130
+ }
2131
+ __name(textExtras2, "textExtras");
2132
+ var optionalKeys = /* @__PURE__ */ __name((value, keys2) => value && typeof value === "object" ? keys2.filter((key) => Object.hasOwn(value, key)) : [], "optionalKeys");
1276
2133
  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();
2134
+ return boundary8(() => {
2135
+ const input = readMlsDataRecord(value, ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId", "text", ...optionalKeys(value, ["replyTo", "mentions"])]);
1281
2136
  return bounded6({
1282
2137
  version: requireMlsLiteral(input.version, 1),
1283
2138
  kind: requireMlsLiteral(input.kind, "text"),
1284
- conversationId: id4(input.conversationId),
1285
- groupId: encoded4(input.groupId, 32),
2139
+ conversationId: id5(input.conversationId),
2140
+ groupId: encoded5(input.groupId, 32),
1286
2141
  messageId: messageId(input.messageId),
1287
- operationId: id4(input.operationId),
2142
+ operationId: id5(input.operationId),
1288
2143
  senderDeviceId: requireMlsUuid(input.senderDeviceId),
1289
- text: input.text
2144
+ text: text2(input.text),
2145
+ ...textExtras2(input)
1290
2146
  });
1291
2147
  });
1292
2148
  }
1293
2149
  __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);
2150
+ var itemFields = ["type", "uploadId", "url", "mimeType", "sizeBytes", "fileName", "width", "height", "durationMs", "thumbnailUrl", "caption", "replyTo", "mentions"];
2151
+ function httpsUrl(value) {
2152
+ if (typeof value !== "string" || value.length > 2048) invalid9();
2153
+ const url = boundary8(() => new URL(value));
2154
+ if (url.protocol !== "https:" || url.username || url.password) invalid9();
2155
+ return value;
2156
+ }
2157
+ __name(httpsUrl, "httpsUrl");
2158
+ var dimension = /* @__PURE__ */ __name((value) => requireMlsInteger(value, 0) <= 1e5 ? value : invalid9(), "dimension");
2159
+ function item(value) {
2160
+ const input = readMlsDataRecord(value, ["type", "uploadId", "url", "mimeType", "sizeBytes", ...optionalKeys(value, itemFields.slice(5))]);
2161
+ 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))
2162
+ invalid9();
2163
+ if (input.fileName !== void 0 && (typeof input.fileName !== "string" || !input.fileName.trim() || [...input.fileName].length > 240))
2164
+ invalid9();
2165
+ return Object.freeze({
2166
+ type: input.type,
2167
+ uploadId: requireMlsUuid(input.uploadId),
2168
+ url: httpsUrl(input.url),
2169
+ mimeType: input.mimeType,
2170
+ sizeBytes: requireMlsInteger(input.sizeBytes, 1),
2171
+ ...input.fileName === void 0 ? {} : { fileName: input.fileName },
2172
+ ...Object.fromEntries(["width", "height", "durationMs"].filter((key) => input[key] !== void 0).map((key) => [key, key === "durationMs" ? requireMlsInteger(input[key], 0) : dimension(input[key])])),
2173
+ ...input.thumbnailUrl === void 0 ? {} : { thumbnailUrl: httpsUrl(input.thumbnailUrl) },
2174
+ ...input.caption === void 0 ? {} : { caption: text2(input.caption) },
2175
+ ...textExtras2(input)
2176
+ });
2177
+ }
2178
+ __name(item, "item");
2179
+ function parseMlsDevItemPayload(value) {
2180
+ return boundary8(() => {
2181
+ const input = readMlsDataRecord(value, ["version", "kind", "conversationId", "groupId", "messageId", "operationId", "senderDeviceId", "item"]);
2182
+ const payload = {
2183
+ version: requireMlsLiteral(input.version, 1),
2184
+ kind: requireMlsLiteral(input.kind, "item"),
2185
+ conversationId: id5(input.conversationId),
2186
+ groupId: encoded5(input.groupId, 32),
2187
+ messageId: messageId(input.messageId),
2188
+ operationId: id5(input.operationId),
2189
+ senderDeviceId: requireMlsUuid(input.senderDeviceId),
2190
+ item: item(input.item)
2191
+ };
2192
+ if (utf85.encode(JSON.stringify(payload)).length > MLS_DEV_TEXT_MAX_BYTES)
2193
+ invalid9();
2194
+ return bounded6(payload);
2195
+ });
2196
+ }
2197
+ __name(parseMlsDevItemPayload, "parseMlsDevItemPayload");
2198
+ function framed(domain4, value, operationId) {
2199
+ const operation = utf85.encode(id5(operationId)), json = utf85.encode(JSON.stringify(value)), prefix = utf85.encode(domain4);
1296
2200
  const result = new Uint8Array(prefix.length + 8 + operation.length + json.length), view = new DataView(result.buffer);
1297
2201
  let offset = 0;
1298
2202
  result.set(prefix, offset);
@@ -1308,7 +2212,7 @@ function framed(domain3, value, operationId) {
1308
2212
  }
1309
2213
  __name(framed, "framed");
1310
2214
  function encodeMlsDevApplicationEnvelopeHash(value, operationId) {
1311
- return boundary6(() => framed("canon.mls.dev-application-envelope.v1\0", parseMlsDevApplicationEnvelope(value), operationId));
2215
+ return boundary8(() => framed("canon.mls.dev-application-envelope.v1\0", parseMlsDevApplicationEnvelope(value), operationId));
1312
2216
  }
1313
2217
  __name(encodeMlsDevApplicationEnvelopeHash, "encodeMlsDevApplicationEnvelopeHash");
1314
2218
 
@@ -1329,12 +2233,6 @@ var RUNTIME_CARD_FIELD_TYPES = [
1329
2233
  "searchSelect",
1330
2234
  "lineItems"
1331
2235
  ];
1332
- var RUNTIME_CARD_LIMITS = {
1333
- detailsRows: 32,
1334
- lineItemRows: 50,
1335
- lineItemColumns: 8,
1336
- searchSelectChoices: 100
1337
- };
1338
2236
  var RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES = [
1339
2237
  "text",
1340
2238
  "number",
@@ -1422,9 +2320,7 @@ var VERB_LIMITS = {
1422
2320
  externalSourceLabelChars: 80,
1423
2321
  /**
1424
2322
  * Contact-request note. Values longer than this are truncated by senders
1425
- * (slice(0,497)+'...') — the truncation is currently triplicated in
1426
- * functions/src/api/sendContextualMessage.ts, packages/core/src/reach-out.ts
1427
- * and the hermes plugin; this constant is the canonical figure.
2323
+ * (slice(0,497)+'...'); this constant is the canonical figure.
1428
2324
  */
1429
2325
  contactRequestNoteChars: 500,
1430
2326
  /** Group membership cap incl. creator (functions/src/utils/conversations.ts MAX_GROUP_MEMBERS). */
@@ -1526,7 +2422,7 @@ var VERB_NATIVE_METADATA_KEYS = [
1526
2422
  "handles"
1527
2423
  ];
1528
2424
  var VERB_NATIVE_STRING_KEYS = VERB_NATIVE_METADATA_KEYS.filter(
1529
- (key2) => key2 !== "handles"
2425
+ (key) => key !== "handles"
1530
2426
  );
1531
2427
  var RUNTIME_CORRELATION_VALUE_PATTERN = new RegExp(
1532
2428
  VERB_ID_PATTERNS.runtimeCorrelationValue
@@ -1728,7 +2624,7 @@ var sessionRuleDef = {
1728
2624
  };
1729
2625
  var runtimeCardDef = {
1730
2626
  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.`,
2627
+ 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
2628
  required: ["schema", "title", "fallbackText", "blocks"],
1733
2629
  additionalProperties: true,
1734
2630
  properties: {
@@ -1845,7 +2741,7 @@ var send_to_input = {
1845
2741
  ]
1846
2742
  };
1847
2743
  var send_to_result = {
1848
- description: "Canonical outcome vocabulary. Legacy binding drift documented in docs/design/verb-bindings.md (hermes 'opened' -> messaged without messageId; hermes 'denied' -> blocked).",
2744
+ description: "Canonical outcome vocabulary.",
1849
2745
  oneOf: [
1850
2746
  {
1851
2747
  type: "object",
@@ -1861,6 +2757,20 @@ var send_to_result = {
1861
2757
  sessionSelection: { type: "string" }
1862
2758
  }
1863
2759
  },
2760
+ {
2761
+ type: "object",
2762
+ required: ["status", "conversationId", "messageId", "openingText"],
2763
+ additionalProperties: true,
2764
+ description: "The room is encrypted, so Canon stored no opening text: the sender sends it encrypted under messageId.",
2765
+ properties: {
2766
+ status: { const: "opened" },
2767
+ conversationId: { type: "string" },
2768
+ messageId: { type: "string" },
2769
+ openingText: { const: "deferred" },
2770
+ created: { type: "boolean" },
2771
+ reused: { type: "boolean" }
2772
+ }
2773
+ },
1864
2774
  {
1865
2775
  type: "object",
1866
2776
  required: ["status", "requestId"],
@@ -1871,6 +2781,12 @@ var send_to_result = {
1871
2781
  deferredIntentId: {
1872
2782
  type: ["string", "null"],
1873
2783
  description: "Present when the send is deferred until the contact request resolves."
2784
+ },
2785
+ conversationId: { type: "string" },
2786
+ messageId: { type: "string" },
2787
+ openingText: {
2788
+ const: "deferred",
2789
+ description: "The room is encrypted, so Canon stored no opening text: the sender sends it encrypted under messageId."
1874
2790
  }
1875
2791
  }
1876
2792
  },
@@ -1910,7 +2826,7 @@ var request_input_input = {
1910
2826
  responseUserId: {
1911
2827
  type: "string",
1912
2828
  pattern: VERB_ID_PATTERNS.runtimeId,
1913
- description: "Must be a human conversation member. Trust-critical bindings (hermes) derive this from turn provenance and ignore model-supplied values."
2829
+ description: "Must be a human conversation member. Trust-critical bindings derive this from turn provenance and ignore model-supplied values."
1914
2830
  },
1915
2831
  native: REF("native"),
1916
2832
  turnId: { type: "string", maxLength: VERB_LIMITS.turnIdChars },
@@ -2755,9 +3671,9 @@ function splitTurnMetadata(metadata) {
2755
3671
  if (!metadata || typeof metadata !== "object") return { turn: void 0, rest: void 0 };
2756
3672
  const turn = {};
2757
3673
  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;
3674
+ for (const [key, value] of Object.entries(metadata)) {
3675
+ if (TURN_KEYS.includes(key)) turn[key] = value;
3676
+ else rest[key] = value;
2761
3677
  }
2762
3678
  return {
2763
3679
  turn: Object.keys(turn).length ? turn : void 0,
@@ -2765,10 +3681,10 @@ function splitTurnMetadata(metadata) {
2765
3681
  };
2766
3682
  }
2767
3683
  __name(splitTurnMetadata, "splitTurnMetadata");
2768
- function compact(record4) {
3684
+ function compact(record5) {
2769
3685
  const out = {};
2770
- for (const [key2, value] of Object.entries(record4)) {
2771
- if (value !== void 0) out[key2] = value;
3686
+ for (const [key, value] of Object.entries(record5)) {
3687
+ if (value !== void 0) out[key] = value;
2772
3688
  }
2773
3689
  return out;
2774
3690
  }
@@ -2948,12 +3864,12 @@ function parseDirectConversationSelection(value) {
2948
3864
  if (!value || typeof value !== "object" || Array.isArray(value)) {
2949
3865
  throw new Error("selection must be an object");
2950
3866
  }
2951
- const record4 = value;
2952
- if (record4.mode === "latest_or_new" || record4.mode === "new") {
2953
- return { mode: record4.mode };
3867
+ const record5 = value;
3868
+ if (record5.mode === "latest_or_new" || record5.mode === "new") {
3869
+ return { mode: record5.mode };
2954
3870
  }
2955
- if (record4.mode === "specific") {
2956
- const conversationId = typeof record4.conversationId === "string" ? record4.conversationId.trim() : "";
3871
+ if (record5.mode === "specific") {
3872
+ const conversationId = typeof record5.conversationId === "string" ? record5.conversationId.trim() : "";
2957
3873
  if (!conversationId) throw new Error("selection.conversationId is required");
2958
3874
  return { mode: "specific", conversationId };
2959
3875
  }
@@ -2978,10 +3894,10 @@ function record(value) {
2978
3894
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
2979
3895
  }
2980
3896
  __name(record, "record");
2981
- function text(value, max) {
3897
+ function text3(value, max) {
2982
3898
  return typeof value === "string" && value.length > 0 && value.length <= max ? value : void 0;
2983
3899
  }
2984
- __name(text, "text");
3900
+ __name(text3, "text");
2985
3901
  function member(value, choices) {
2986
3902
  return choices.includes(value) ? value : void 0;
2987
3903
  }
@@ -3016,19 +3932,19 @@ function normalizeDispatch(value) {
3016
3932
  return primitive ? { kind: "primitive", primitive } : void 0;
3017
3933
  }
3018
3934
  case "control": {
3019
- const controlId = text(dispatch.controlId, 128);
3020
- return controlId ? defined({ kind: "control", controlId, value: text(dispatch.value, 1024) }) : void 0;
3935
+ const controlId = text3(dispatch.controlId, 128);
3936
+ return controlId ? defined({ kind: "control", controlId, value: text3(dispatch.value, 1024) }) : void 0;
3021
3937
  }
3022
3938
  case "text_passthrough": {
3023
- const template = text(dispatch.template, 2048);
3939
+ const template = text3(dispatch.template, 2048);
3024
3940
  return template ? { kind: "text_passthrough", template } : void 0;
3025
3941
  }
3026
3942
  case "compose": {
3027
- const content = text(dispatch.text, 2048);
3943
+ const content = text3(dispatch.text, 2048);
3028
3944
  return content ? { kind: "compose", text: content } : void 0;
3029
3945
  }
3030
3946
  case "open_details":
3031
- return defined({ kind: "open_details", target: text(dispatch.target, 128) });
3947
+ return defined({ kind: "open_details", target: text3(dispatch.target, 128) });
3032
3948
  default:
3033
3949
  return void 0;
3034
3950
  }
@@ -3036,21 +3952,21 @@ function normalizeDispatch(value) {
3036
3952
  __name(normalizeDispatch, "normalizeDispatch");
3037
3953
  function normalizeArgument(value) {
3038
3954
  const arg = record(value);
3039
- const id6 = text(arg.id, 128);
3040
- const label = text(arg.label, 160);
3955
+ const id7 = text3(arg.id, 128);
3956
+ const label = text3(arg.label, 160);
3041
3957
  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;
3958
+ if (!id7 || !label || !kind) return void 0;
3959
+ if (["required", "captureRemaining"].some((key) => arg[key] !== void 0 && typeof arg[key] !== "boolean")) return void 0;
3044
3960
  if (arg.choices !== void 0 && !Array.isArray(arg.choices)) return void 0;
3045
3961
  const choices = Array.isArray(arg.choices) ? arg.choices.slice(0, 128).flatMap((value2) => {
3046
3962
  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) })] : [];
3963
+ const entry = text3(choice.value, 1024);
3964
+ const label2 = text3(choice.label, 160);
3965
+ return entry && label2 ? [defined({ value: entry, label: label2, description: text3(choice.description, 1024) })] : [];
3050
3966
  }) : void 0;
3051
3967
  if (kind === "enum" && !choices?.length) return void 0;
3052
3968
  return defined({
3053
- id: id6,
3969
+ id: id7,
3054
3970
  label,
3055
3971
  kind,
3056
3972
  choices,
@@ -3064,15 +3980,15 @@ function normalizePublicRuntimeCommands(value) {
3064
3980
  const seenIds = /* @__PURE__ */ new Set();
3065
3981
  const seenAliases = /* @__PURE__ */ new Set();
3066
3982
  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);
3983
+ for (const item2 of value.slice(0, MAX_PUBLIC_RUNTIME_COMMANDS)) {
3984
+ const command = record(item2);
3985
+ const id7 = text3(command.id, 128);
3986
+ const label = text3(command.label, 160);
3071
3987
  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];
3988
+ if (!id7 || !label || !dispatch || seenIds.has(id7) || command.visibility === "hidden" || command.sensitive === true) continue;
3989
+ if (["ownerOnly", "sensitive"].some((key) => command[key] !== void 0 && typeof command[key] !== "boolean")) continue;
3990
+ if (["aliases", "args", "placements", "availability"].some((key) => command[key] !== void 0 && !Array.isArray(command[key]))) continue;
3991
+ const rawAliases = Array.isArray(command.aliases) && command.aliases.length ? command.aliases : [id7];
3076
3992
  const aliases = [...new Set(rawAliases.slice(0, 8).flatMap((value2) => {
3077
3993
  const alias = typeof value2 === "string" && value2.length <= 128 ? normalizeRuntimeCommandAlias(value2) : null;
3078
3994
  return alias && /^[A-Za-z0-9:_-]+$/.test(alias) && !seenAliases.has(alias.toLowerCase()) ? [alias] : [];
@@ -3080,20 +3996,20 @@ function normalizePublicRuntimeCommands(value) {
3080
3996
  if (!aliases.length) continue;
3081
3997
  const args = Array.isArray(command.args) ? command.args.slice(0, 12).map(normalizeArgument) : void 0;
3082
3998
  if (args?.some((arg) => !arg) || Array.isArray(command.args) && command.args.length > 12) continue;
3083
- seenIds.add(id6);
3999
+ seenIds.add(id7);
3084
4000
  aliases.forEach((alias) => seenAliases.add(alias.toLowerCase()));
3085
4001
  result.push(defined({
3086
- id: id6,
4002
+ id: id7,
3087
4003
  label,
3088
4004
  aliases,
3089
4005
  dispatch,
3090
4006
  args,
3091
- description: text(command.description, 1024),
4007
+ description: text3(command.description, 1024),
3092
4008
  category: member(command.category, ["plan", "turn", "session", "runtime", "details", "skill", "custom"]),
3093
4009
  placements: members(command.placements, ["composer_slash", "command_palette", "session_strip"]),
3094
4010
  availability: members(command.availability, ["idle", "busy", "busy_with_queue", "waiting_input", "always"]),
3095
4011
  ownerOnly: typeof command.ownerOnly === "boolean" ? command.ownerOnly : void 0,
3096
- disabledReason: text(command.disabledReason, 1024),
4012
+ disabledReason: text3(command.disabledReason, 1024),
3097
4013
  trailingTextBehavior: member(command.trailingTextBehavior, ["ignore", "send_as_prompt"]),
3098
4014
  primitive: member(command.primitive, PRIMITIVES),
3099
4015
  tier: member(command.tier, ["primary", "detail", "diagnostic"])
@@ -3127,14 +4043,14 @@ function normalizePublicRuntimeFacts(value) {
3127
4043
  const seen = /* @__PURE__ */ new Set();
3128
4044
  return value.slice(0, 16).flatMap((entry) => {
3129
4045
  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);
4046
+ const id7 = text3(fact.id, 64);
4047
+ const group = id7 && Object.hasOwn(PUBLIC_RUNTIME_FACT_GROUPS, id7) ? PUBLIC_RUNTIME_FACT_GROUPS[id7] : void 0;
4048
+ const label = text3(fact.label, 80);
4049
+ const content = text3(fact.value, 512);
4050
+ if (!id7 || !group || !label || !content || seen.has(id7) || fact.sensitive === true || fact.visibility === "hidden") return [];
4051
+ seen.add(id7);
3136
4052
  return [defined({
3137
- id: id6,
4053
+ id: id7,
3138
4054
  group,
3139
4055
  label,
3140
4056
  value: content,
@@ -3147,13 +4063,8 @@ function normalizePublicRuntimeFacts(value) {
3147
4063
  }
3148
4064
  __name(normalizePublicRuntimeFacts, "normalizePublicRuntimeFacts");
3149
4065
 
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
4066
  // ../backend-contracts/src/endpointContentPolicy.ts
3156
- var MLS_DEV_UNSUPPORTED_CONTENT_ACTIONS = ["delete_message", "forward_message"];
4067
+ var MLS_DEV_UNSUPPORTED_CONTENT_ACTIONS = ["forward_message"];
3157
4068
  var ENDPOINT_CONTENT_ACTIONS = [
3158
4069
  "mls_application",
3159
4070
  "mls_group_control",
@@ -3161,8 +4072,6 @@ var ENDPOINT_CONTENT_ACTIONS = [
3161
4072
  "append_artifact_command",
3162
4073
  "retain_artifact_asset",
3163
4074
  "sync_phone_contacts",
3164
- "request_work_session",
3165
- "resolve_work_session_request",
3166
4075
  "update_agent_behavior_policy",
3167
4076
  "update_conversation_agent_behavior_policy",
3168
4077
  "send_message",
@@ -3215,6 +4124,8 @@ var ENDPOINT_CONTENT_ACTIONS = [
3215
4124
  var ENDPOINT_CONTENT_FUNCTION_QUERIES = [
3216
4125
  "mls_group_feed",
3217
4126
  "mls_group_controls",
4127
+ "mls_group_admissions",
4128
+ "mls_interactions",
3218
4129
  "list_artifacts",
3219
4130
  "get_artifact_log",
3220
4131
  "get_artifact_asset",
@@ -3222,9 +4133,6 @@ var ENDPOINT_CONTENT_FUNCTION_QUERIES = [
3222
4133
  "get_unread_summary",
3223
4134
  "peek_runtime_signal",
3224
4135
  "list_runtime_primitives",
3225
- "get_work_session_catalog",
3226
- "get_work_session_details",
3227
- "get_work_session_request",
3228
4136
  "get_agent_behavior_policy",
3229
4137
  "get_conversation_agent_behavior_policy",
3230
4138
  "get_ephemeral",
@@ -3246,7 +4154,8 @@ var ENDPOINT_CONTENT_FUNCTION_QUERIES = [
3246
4154
  "get_media_message",
3247
4155
  "get_voice_session",
3248
4156
  "get_image_generation",
3249
- "get_image_generation_status"
4157
+ "get_image_generation_status",
4158
+ "same_owner_agents"
3250
4159
  ];
3251
4160
  var ENDPOINT_CONTENT_QUERIES = [...ENDPOINT_CONTENT_FUNCTION_QUERIES, "admit_messages"];
3252
4161
  var ENDPOINT_CONTENT_EPHEMERALS = [
@@ -3360,7 +4269,8 @@ var actionRouting = {
3360
4269
  send_message: ["conversationId", "messageId", "replyTo", "mentions.*"],
3361
4270
  delete_message: ["conversationId", "messageId"],
3362
4271
  forward_message: ["sourceConversationId", "targetConversationId", "messageId"],
3363
- react: ["conversationId", "messageId"],
4272
+ // A reaction is an action on a message's public stub, so its emoji is server-visible in encrypted rooms too (ruling 3).
4273
+ react: ["conversationId", "messageId", "emoji"],
3364
4274
  send_contextual_message: ["conversationId"],
3365
4275
  create_interaction: ["conversationId", "requestId", "inputId", "approvalId", "cardId", "planId", "responseUserId"],
3366
4276
  consume_interaction: ["conversationId", "inputId", "approvalId", "cardId", "planId"],
@@ -3381,13 +4291,19 @@ var actionRouting = {
3381
4291
  set_block: ["targetUserId"],
3382
4292
  save_contact: ["contactUserId"],
3383
4293
  remove_contact: ["contactId", "contactUserId"],
3384
- session_control: ["conversationId", "agentId"],
4294
+ // `signal.type` is the closed Stop family (interrupt, stop_and_drop, new_session) the server must read to deliver it;
4295
+ // a runtime `primitive` (commands, arguments) stays private, so it remains refused in encrypted rooms.
4296
+ session_control: ["conversationId", "agentId", "signal.type"],
3385
4297
  approve_contact_request: ["requestId"],
3386
4298
  reject_contact_request: ["requestId"],
3387
4299
  cancel_direct_request: ["requestId"],
3388
4300
  update_message_disposition: ["conversationId", "messageId"],
3389
- create_upload: ["conversationId"],
4301
+ // An encrypted room's item uploads its bytes as in a plaintext room (they are not end-to-end encrypted, payload v3
4302
+ // §4): the type, size and display hints are public; its file name and caption ride only inside the item.
4303
+ create_upload: ["conversationId", "mimeType", "sizeBytes", "width", "height", "durationMs"],
3390
4304
  finalize_upload: ["uploadId"],
4305
+ // An encrypted item's application names its uploads beside the ciphertext, for Canon to retain on acceptance.
4306
+ mls_application: ["mediaUploadIds.*"],
3391
4307
  delete_upload: ["uploadId"],
3392
4308
  retry_video_processing: ["uploadId"],
3393
4309
  stage_media_message: ["conversationId", "messageId", "files.*.fileId", "contentVersion", ...preparedRoutingPaths.map((path) => `preparedContent.${path}`)],
@@ -3395,19 +4311,18 @@ var actionRouting = {
3395
4311
  renew_media_message_upload: ["conversationId", "messageId", "fileId", "generation"],
3396
4312
  finalize_memo_stream: ["conversationId", "streamId"],
3397
4313
  abort_memo_stream: ["streamId"],
3398
- create_voice_session: ["conversationId"],
4314
+ create_voice_session: ["conversationId", "media"],
3399
4315
  join_voice_session: ["conversationId", "sessionId"],
3400
4316
  decline_voice_session: ["conversationId", "sessionId"],
3401
4317
  end_voice_session: ["conversationId", "sessionId"],
3402
4318
  consume_runtime_signal: ["conversationId", "expectedSignalId"],
3403
4319
  consume_runtime_primitive: ["conversationId", "requestId", "expectedRevision"],
3404
4320
  generate_image: ["conversationId", "requestId"],
3405
- request_work_session: ["conversationId", "agentId", "requestId"],
3406
- resolve_work_session_request: ["requestId"],
3407
4321
  update_agent_behavior_policy: ["agentId"],
3408
4322
  update_conversation_agent_behavior_policy: ["conversationId", "agentId"]
3409
4323
  };
3410
4324
  var queryRouting = {
4325
+ mls_interactions: ["version", "conversationId"],
3411
4326
  list_artifacts: ["conversationId", "cursor", "limit"],
3412
4327
  get_artifact_log: ["conversationId", "artifactId", "afterSequence", "cursor", "limit"],
3413
4328
  get_artifact_asset: ["conversationId", "artifactId", "assetId"],
@@ -3433,12 +4348,19 @@ var queryRouting = {
3433
4348
  get_media_message: ["conversationId", "messageId", "installationId"],
3434
4349
  get_voice_session: ["conversationId", "sessionId"],
3435
4350
  get_image_generation: ["requestId"],
3436
- get_work_session_catalog: ["agentId"],
3437
- get_work_session_details: ["agentId", "conversationId"],
3438
- get_work_session_request: ["requestId"],
4351
+ same_owner_agents: ["agentIds.*"],
3439
4352
  get_agent_behavior_policy: ["agentId"],
3440
4353
  get_conversation_agent_behavior_policy: ["conversationId", "agentId"]
3441
4354
  };
4355
+ var ENDPOINT_TURN_PRESENCE_STATES = ["thinking", "waiting_input", "interrupted", "idle"];
4356
+ var timestamp = /* @__PURE__ */ __name((value) => value === null || Number.isSafeInteger(value) && value >= 0, "timestamp");
4357
+ var turnPresence = {
4358
+ state: /* @__PURE__ */ __name((value) => ENDPOINT_TURN_PRESENCE_STATES.includes(value), "state"),
4359
+ // `turn-` and 32 random hex digits per encrypted turn: never the runner's own turn id, which seeds its cards' request ids.
4360
+ turnId: /* @__PURE__ */ __name((value) => value === null || typeof value === "string" && /^turn-[0-9a-f]{32}$/.test(value), "turnId"),
4361
+ openedAt: timestamp,
4362
+ turnUpdatedAt: timestamp
4363
+ };
3442
4364
  var transientRouting = {
3443
4365
  create_memo_stream: ["conversationId", "streamId"],
3444
4366
  append_memo_chunk: ["streamId"],
@@ -3478,7 +4400,7 @@ function endpointOperationRequestRetention(action, body, envelope) {
3478
4400
  if (action !== "respond_interaction") return "journal";
3479
4401
  if (envelope && Object.keys(envelope).length > 0) return "memory";
3480
4402
  const routing = ["kind", "conversationId", "agentId", "requestId"];
3481
- const hasOnly = /* @__PURE__ */ __name((fields) => Object.keys(body).every((field) => fields.includes(field)), "hasOnly");
4403
+ const hasOnly = /* @__PURE__ */ __name((fields2) => Object.keys(body).every((field) => fields2.includes(field)), "hasOnly");
3482
4404
  if (routing.some((field) => body[field] !== void 0 && typeof body[field] !== "string")) return "memory";
3483
4405
  if ((body.kind === "input" || body.kind === "card") && hasOnly([...routing, "status", "actionId"])) {
3484
4406
  if (!["submitted", "cancelled"].includes(String(body.status)) || body.actionId !== void 0 && typeof body.actionId !== "string") return "memory";
@@ -3501,8 +4423,8 @@ function endpointOperationRequestRetention(action, body, envelope) {
3501
4423
  __name(endpointOperationRequestRetention, "endpointOperationRequestRetention");
3502
4424
  function endpointContentBoundary(lane, name, payload) {
3503
4425
  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)) {
4426
+ const record5 = payload && typeof payload === "object" ? payload : void 0;
4427
+ if (lane === "query.request" && name === "get_ephemeral" && record5 && !ENDPOINT_CONTENT_EPHEMERAL_FAMILIES.includes(record5.family)) {
3506
4428
  throw new EndpointContentPolicyError(lane, `${name}/unknown-family`);
3507
4429
  }
3508
4430
  const requestRoutingPaths = (actionRouting[name] ?? []).flatMap((field) => [`body.value.${field}`, `envelope.${field}`]);
@@ -3510,7 +4432,7 @@ function endpointContentBoundary(lane, name, payload) {
3510
4432
  if (path.some((part) => secretSegments.has(part))) return "restricted-secret";
3511
4433
  if (lane === "operation.request" && ["respond_interaction", "sync_phone_contacts"].includes(name) && matches(path, "preparedContent.payload")) return "restricted-secret";
3512
4434
  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";
4435
+ if (lane === "operation.receipt" && path[0] === "result" && (["consume_interaction", "respond_interaction"].includes(name) || record5?.resultReference?.kind === "interaction")) return "restricted-secret";
3514
4436
  let selected = payload;
3515
4437
  for (const part of path) selected = selected && typeof selected === "object" && Object.hasOwn(selected, part) ? selected[part] : void 0;
3516
4438
  if (selected !== null && typeof selected === "object") return "private-content";
@@ -3519,8 +4441,8 @@ function endpointContentBoundary(lane, name, payload) {
3519
4441
  if (name === "respond_interaction" && path[0] === "body" && path[1] === "value") return "restricted-secret";
3520
4442
  if (name === "sync_phone_contacts" && path[0] === "body" && path[1] === "value") return "restricted-secret";
3521
4443
  if (name === "verb_execute") {
3522
- const wire3 = record4?.body?.value;
3523
- const spec = VERB_WIRE_ENVELOPE_FIELDS[wire3?.verb];
4444
+ const wire4 = record5?.body?.value;
4445
+ const spec = VERB_WIRE_ENVELOPE_FIELDS[wire4?.verb];
3524
4446
  if (path[0] === "body" && path[1] === "value") {
3525
4447
  if (path.length === 3 && ["wire", "verb"].includes(path[2])) return "public-metadata";
3526
4448
  if (path[2] === "envelope" && spec) {
@@ -3532,7 +4454,7 @@ function endpointContentBoundary(lane, name, payload) {
3532
4454
  }
3533
4455
  } else if (lane === "operation.receipt") {
3534
4456
  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";
4457
+ if (path[0] === "result" && (name === "consume_interaction" || name === "respond_interaction" || record5?.resultReference?.kind === "interaction")) return "restricted-secret";
3536
4458
  } else if (lane === "query.request") {
3537
4459
  if (publicMatch(path, queryRouting[name] ?? [])) return "public-metadata";
3538
4460
  } else if (lane === "query.result" || lane === "ephemeral.result") {
@@ -3540,6 +4462,7 @@ function endpointContentBoundary(lane, name, payload) {
3540
4462
  if (name === "get_ephemeral" && path[0] === "value") return "private-content";
3541
4463
  } else if (lane === "ephemeral.request") {
3542
4464
  if (publicMatch(path, transientRouting[name] ?? [])) return "public-metadata";
4465
+ if (name === "publish_turn" && path.length === 1 && Object.hasOwn(turnPresence, path[0]) && turnPresence[path[0]](selected)) return "public-metadata";
3543
4466
  } else if (lane === "event") {
3544
4467
  if (publicMatch(path, eventRouting(name))) return "public-metadata";
3545
4468
  }
@@ -3563,12 +4486,12 @@ var PreparedContentError = class extends Error {
3563
4486
  __name(this, "PreparedContentError");
3564
4487
  }
3565
4488
  };
3566
- function invalid8() {
4489
+ function invalid10() {
3567
4490
  throw new PreparedContentError("INVALID_PREPARED_CONTENT");
3568
4491
  }
3569
- __name(invalid8, "invalid");
4492
+ __name(invalid10, "invalid");
3570
4493
  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");
4494
+ var keys = /* @__PURE__ */ __name((value, allowed) => Object.keys(value).every((key) => allowed.includes(key)), "keys");
3572
4495
  var revision = /* @__PURE__ */ __name((value) => Number.isSafeInteger(value) && value >= 0, "revision");
3573
4496
  var blobIdentity = /* @__PURE__ */ __name((value) => typeof value === "string" && value.length > 0 && value.length <= 1024 && !/[\u0000-\u001f]/.test(value), "blobIdentity");
3574
4497
  var identity = /* @__PURE__ */ __name((value) => typeof value === "string" && ENDPOINT_ID_PATTERN.test(value), "identity");
@@ -3579,33 +4502,33 @@ function canonicalEndpointJson(value) {
3579
4502
  function encode(input) {
3580
4503
  if (input === null || typeof input !== "object") return JSON.stringify(input);
3581
4504
  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(",")}}`;
4505
+ const object = input;
4506
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${encode(object[key])}`).join(",")}}`;
3584
4507
  }
3585
4508
  __name(encode, "encode");
3586
4509
  return encode(normalized);
3587
4510
  }
3588
4511
  __name(canonicalEndpointJson, "canonicalEndpointJson");
3589
4512
  function validateMetadata(value) {
3590
- if (!record2(value)) invalid8();
4513
+ if (!record2(value)) invalid10();
3591
4514
  if (value.version !== PREPARED_CONTENT_VERSION) throw new PreparedContentError("UNSUPPORTED_PREPARED_CONTENT_VERSION");
3592
4515
  if (value.codec !== PREPARED_JSON_CODEC) throw new PreparedContentError("UNSUPPORTED_PREPARED_CONTENT_CODEC");
3593
- if (!keys(value, ["version", "context", "codec", "payload", "blobs", "expected"])) invalid8();
4516
+ if (!keys(value, ["version", "context", "codec", "payload", "blobs", "expected"])) invalid10();
3594
4517
  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();
4518
+ 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
4519
  const expected = value.expected;
3597
- if (!record2(expected) || !keys(expected, ["installationGeneration", "protocolRevision", "admission"]) || !revision(expected.installationGeneration) || !revision(expected.protocolRevision)) invalid8();
4520
+ if (!record2(expected) || !keys(expected, ["installationGeneration", "protocolRevision", "admission"]) || !revision(expected.installationGeneration) || !revision(expected.protocolRevision)) invalid10();
3598
4521
  if (expected.admission !== void 0) {
3599
4522
  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();
4523
+ 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
4524
  }
3602
- if (!Array.isArray(value.blobs)) invalid8();
4525
+ if (!Array.isArray(value.blobs)) invalid10();
3603
4526
  const ids = /* @__PURE__ */ new Set();
3604
4527
  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();
4528
+ if (!record2(blob) || !keys(blob, ["id", "index"]) || !blobIdentity(blob.id) || blob.index !== index || ids.has(blob.id)) invalid10();
3606
4529
  ids.add(blob.id);
3607
4530
  }
3608
- if (typeof value.payload !== "string") invalid8();
4531
+ if (typeof value.payload !== "string") invalid10();
3609
4532
  }
3610
4533
  __name(validateMetadata, "validateMetadata");
3611
4534
  function decodePreparedJsonContent(value) {
@@ -3614,18 +4537,18 @@ function decodePreparedJsonContent(value) {
3614
4537
  try {
3615
4538
  decoded = JSON.parse(value.payload);
3616
4539
  } catch {
3617
- invalid8();
4540
+ invalid10();
3618
4541
  }
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();
4542
+ if (!record2(decoded) || !keys(decoded, ["body", "envelope"]) || !record2(decoded.body) || decoded.envelope !== void 0 && !record2(decoded.envelope)) invalid10();
4543
+ if (canonicalEndpointJson(decoded) !== value.payload) invalid10();
3621
4544
  const { body, envelope } = decoded;
3622
4545
  if (endpointOperationRequestRetention(value.context.action, body, envelope) === "memory") {
3623
4546
  throw new PreparedContentError("PREPARED_CONTENT_MEMORY_ONLY");
3624
4547
  }
3625
4548
  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();
4549
+ for (const key of ["conversationId", "messageId"]) {
4550
+ const bound = value.context[key];
4551
+ if (bound !== void 0 && effective[key] !== void 0 && effective[key] !== bound) invalid10();
3629
4552
  }
3630
4553
  return envelope === void 0 ? { body } : { body, envelope };
3631
4554
  }
@@ -3655,7 +4578,7 @@ function prepareJsonContent(input) {
3655
4578
  }
3656
4579
  __name(prepareJsonContent, "prepareJsonContent");
3657
4580
  function logicalMediaBlobId(conversationId, messageId2, index) {
3658
- if (!identity(conversationId) || !identity(messageId2) || !revision(index)) invalid8();
4581
+ if (!identity(conversationId) || !identity(messageId2) || !revision(index)) invalid10();
3659
4582
  return JSON.stringify([conversationId, messageId2, index]);
3660
4583
  }
3661
4584
  __name(logicalMediaBlobId, "logicalMediaBlobId");
@@ -3671,10 +4594,130 @@ function isEndpointOperationReceipt(value) {
3671
4594
  }
3672
4595
  __name(isEndpointOperationReceipt, "isEndpointOperationReceipt");
3673
4596
 
4597
+ // ../backend-contracts/src/connectorRelay.ts
4598
+ var CONNECTOR_RELAY_INSTALLATION_PREFIX = "canon-relay:";
4599
+ var CONNECTOR_RELAY_INSTALLATION_PATTERN = /^canon-relay:[0-9a-f]{40}$/;
4600
+ function isConnectorRelayInstallation(installationId) {
4601
+ return typeof installationId === "string" && installationId.startsWith(CONNECTOR_RELAY_INSTALLATION_PREFIX);
4602
+ }
4603
+ __name(isConnectorRelayInstallation, "isConnectorRelayInstallation");
4604
+ var CONNECTOR_RELAY_CREDENTIAL_PATTERN = /^canon_relay_[A-Za-z0-9_-]{43}$/;
4605
+ function isConnectorRelayCredential(value) {
4606
+ return typeof value === "string" && CONNECTOR_RELAY_CREDENTIAL_PATTERN.test(value);
4607
+ }
4608
+ __name(isConnectorRelayCredential, "isConnectorRelayCredential");
4609
+ var CONNECTOR_RELAY_INPUT_ID_PATTERN = /^relay:[0-9a-f]{40}$/;
4610
+ var CONNECTOR_RELAY_MAX_BODY_BYTES = 256 * 1024;
4611
+ var CONNECTOR_RELAY_MAX_TEXT_BYTES = MLS_DEV_TEXT_MAX_BYTES;
4612
+ var CONNECTOR_RELAY_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
4613
+ var CONNECTOR_RELAY_ANSWER_WITHIN_MS = 7e3;
4614
+ function connectorRelayResponseBytes(value) {
4615
+ return new TextEncoder().encode(JSON.stringify(value)).length;
4616
+ }
4617
+ __name(connectorRelayResponseBytes, "connectorRelayResponseBytes");
4618
+ var ConnectorRelayRequestError = class extends Error {
4619
+ static {
4620
+ __name(this, "ConnectorRelayRequestError");
4621
+ }
4622
+ name = "ConnectorRelayRequestError";
4623
+ };
4624
+ function invalid11(what) {
4625
+ throw new ConnectorRelayRequestError(`Invalid relay request: ${what}`);
4626
+ }
4627
+ __name(invalid11, "invalid");
4628
+ function record3(value, required, optional = []) {
4629
+ if (!value || typeof value !== "object" || Array.isArray(value)) invalid11("expected an object");
4630
+ const result = value;
4631
+ for (const key of Object.keys(result)) if (!required.includes(key) && !optional.includes(key)) invalid11(`unexpected ${key}`);
4632
+ for (const key of required) if (!Object.hasOwn(result, key)) invalid11(`missing ${key}`);
4633
+ return result;
4634
+ }
4635
+ __name(record3, "record");
4636
+ function id6(value, what, pattern = ENDPOINT_ID_PATTERN) {
4637
+ if (typeof value !== "string" || !pattern.test(value)) invalid11(what);
4638
+ return value;
4639
+ }
4640
+ __name(id6, "id");
4641
+ function doc(value, what) {
4642
+ if (typeof value !== "string" || !value || value.length > 200 || value.includes("/")) invalid11(what);
4643
+ return value;
4644
+ }
4645
+ __name(doc, "doc");
4646
+ var room = /* @__PURE__ */ __name((value) => doc(value, "conversationId"), "room");
4647
+ function text4(value) {
4648
+ if (typeof value !== "string" || !value.trim() || new TextEncoder().encode(value).length > CONNECTOR_RELAY_MAX_TEXT_BYTES) invalid11("text");
4649
+ return value;
4650
+ }
4651
+ __name(text4, "text");
4652
+ function limit(value) {
4653
+ if (value === void 0) return void 0;
4654
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > 100) invalid11("limit");
4655
+ return value;
4656
+ }
4657
+ __name(limit, "limit");
4658
+ function parseConnectorRelayRequest(value) {
4659
+ const body = record3(value, ["version", "agentId", "grantId", "op", "args"]);
4660
+ if (body.version !== 1) invalid11("version");
4661
+ const head = { version: 1, agentId: doc(body.agentId, "agentId"), grantId: id6(body.grantId, "grantId") };
4662
+ switch (body.op) {
4663
+ case "pending": {
4664
+ const args = record3(body.args, ["conversationId"], ["limit"]);
4665
+ return { ...head, op: "pending", args: { conversationId: room(args.conversationId), ...args.limit === void 0 ? {} : { limit: limit(args.limit) } } };
4666
+ }
4667
+ case "claim": {
4668
+ const args = record3(body.args, ["inputId", "requestId"]);
4669
+ return { ...head, op: "claim", args: { inputId: id6(args.inputId, "inputId", CONNECTOR_RELAY_INPUT_ID_PATTERN), requestId: id6(args.requestId, "requestId") } };
4670
+ }
4671
+ case "reply": {
4672
+ const args = record3(body.args, ["inputId", "requestId", "text"]);
4673
+ return { ...head, op: "reply", args: {
4674
+ inputId: id6(args.inputId, "inputId", CONNECTOR_RELAY_INPUT_ID_PATTERN),
4675
+ requestId: id6(args.requestId, "requestId"),
4676
+ text: text4(args.text)
4677
+ } };
4678
+ }
4679
+ case "settle": {
4680
+ const args = record3(body.args, ["inputId", "requestId", "outcome"]);
4681
+ if (!["completed", "no_reply", "failed"].includes(args.outcome)) invalid11("outcome");
4682
+ return { ...head, op: "settle", args: {
4683
+ inputId: id6(args.inputId, "inputId", CONNECTOR_RELAY_INPUT_ID_PATTERN),
4684
+ requestId: id6(args.requestId, "requestId"),
4685
+ outcome: args.outcome
4686
+ } };
4687
+ }
4688
+ case "read": {
4689
+ const args = record3(body.args, ["conversationId"], ["limit", "before"]);
4690
+ if (args.before !== void 0 && (typeof args.before !== "string" || !/^[1-9][0-9]{0,15}$/.test(args.before))) invalid11("before");
4691
+ return { ...head, op: "read", args: {
4692
+ conversationId: room(args.conversationId),
4693
+ ...args.limit === void 0 ? {} : { limit: limit(args.limit) },
4694
+ ...args.before === void 0 ? {} : { before: args.before }
4695
+ } };
4696
+ }
4697
+ case "send": {
4698
+ const args = record3(body.args, ["conversationId", "messageId", "text"]);
4699
+ return { ...head, op: "send", args: { conversationId: room(args.conversationId), messageId: id6(args.messageId, "messageId"), text: text4(args.text) } };
4700
+ }
4701
+ case "credential": {
4702
+ const args = record3(body.args, ["installationId", "generation", "credential"]);
4703
+ if (!Number.isSafeInteger(args.generation) || args.generation < 1) invalid11("generation");
4704
+ if (!isConnectorRelayCredential(args.credential)) invalid11("credential");
4705
+ return { ...head, op: "credential", args: {
4706
+ installationId: id6(args.installationId, "installationId", CONNECTOR_RELAY_INSTALLATION_PATTERN),
4707
+ generation: args.generation,
4708
+ credential: args.credential
4709
+ } };
4710
+ }
4711
+ default:
4712
+ return invalid11("op");
4713
+ }
4714
+ }
4715
+ __name(parseConnectorRelayRequest, "parseConnectorRelayRequest");
4716
+
3674
4717
  // ../backend-contracts/src/deliveryObservation.ts
3675
4718
  var isTerminalDeliveryOutcome = /* @__PURE__ */ __name((outcome) => !["unknown", "pending"].includes(outcome), "isTerminalDeliveryOutcome");
3676
4719
  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;
4720
+ 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
4721
  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
4722
  return next;
3680
4723
  }
@@ -3695,7 +4738,7 @@ __name(classifyTransferHttpFailure, "classifyTransferHttpFailure");
3695
4738
  function classifyTransferReceipt(value, expected) {
3696
4739
  if (!value || typeof value !== "object" || Array.isArray(value)) return "invalid";
3697
4740
  const receipt = value;
3698
- if (Object.entries(expected).some(([key2, field]) => receipt[key2] !== field)) return "invalid";
4741
+ if (Object.entries(expected).some(([key, field]) => receipt[key] !== field)) return "invalid";
3699
4742
  switch (receipt.status) {
3700
4743
  case "succeeded":
3701
4744
  return "resultError" in receipt || !receipt.result || typeof receipt.result !== "object" || Array.isArray(receipt.result) ? "uncertain" : "result";
@@ -3712,17 +4755,8 @@ function classifyTransferReceipt(value, expected) {
3712
4755
  __name(classifyTransferReceipt, "classifyTransferReceipt");
3713
4756
 
3714
4757
  // ../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
4758
  var ARTIFACT_COMMAND_MAX_BYTES = 64 * 1024;
3719
4759
  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
4760
  var ARTIFACT_LIMITS = Object.freeze({
3727
4761
  titleChars: 120,
3728
4762
  chessMaxPlies: 600,
@@ -3747,604 +4781,7 @@ var ARTIFACT_LIMITS = Object.freeze({
3747
4781
  outcomes: 200,
3748
4782
  outcomeMessageChars: 500
3749
4783
  });
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
4784
  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
4785
 
4349
4786
  // ../backend-contracts/src/mlsDevCredentialReconciliation.ts
4350
4787
  var MLS_DEV_CREDENTIAL_RECONCILIATION_CHALLENGE_TTL_MS = 3e5;
@@ -4359,32 +4796,32 @@ var MlsDevCredentialReconciliationValidationError = class extends Error {
4359
4796
  this.name = "MlsDevCredentialReconciliationValidationError";
4360
4797
  }
4361
4798
  };
4362
- var utf85 = new TextEncoder();
4363
- var domain2 = utf85.encode("canon.mls.credential-reconciliation-proof.v1\0");
4364
- function invalid9() {
4799
+ var utf86 = new TextEncoder();
4800
+ var domain2 = utf86.encode("canon.mls.credential-reconciliation-proof.v1\0");
4801
+ function invalid12() {
4365
4802
  throw new MlsDevCredentialReconciliationValidationError();
4366
4803
  }
4367
- __name(invalid9, "invalid");
4368
- function boundary7(read) {
4804
+ __name(invalid12, "invalid");
4805
+ function boundary9(read) {
4369
4806
  try {
4370
4807
  return read();
4371
4808
  } catch {
4372
- return invalid9();
4809
+ return invalid12();
4373
4810
  }
4374
4811
  }
4375
- __name(boundary7, "boundary");
4812
+ __name(boundary9, "boundary");
4376
4813
  function bounded7(value) {
4377
- if (utf85.encode(JSON.stringify(value)).length > MLS_DEV_CREDENTIAL_RECONCILIATION_MAX_BYTES) invalid9();
4814
+ if (utf86.encode(JSON.stringify(value)).length > MLS_DEV_CREDENTIAL_RECONCILIATION_MAX_BYTES) invalid12();
4378
4815
  return Object.freeze(value);
4379
4816
  }
4380
4817
  __name(bounded7, "bounded");
4381
- function encoded5(value, bytes) {
4818
+ function encoded6(value, bytes) {
4382
4819
  decodeCanonicalMlsBase64Url(value, bytes);
4383
4820
  return value;
4384
4821
  }
4385
- __name(encoded5, "encoded");
4822
+ __name(encoded6, "encoded");
4386
4823
  function parseMlsDevCredentialReconciliationBegin(value) {
4387
- return boundary7(() => {
4824
+ return boundary9(() => {
4388
4825
  const input = readMlsDataRecord(value, ["version", "deviceId", "requestId", "expectedCredentialGeneration"]);
4389
4826
  return bounded7({
4390
4827
  version: requireMlsLiteral(input.version, 1),
@@ -4396,7 +4833,7 @@ function parseMlsDevCredentialReconciliationBegin(value) {
4396
4833
  }
4397
4834
  __name(parseMlsDevCredentialReconciliationBegin, "parseMlsDevCredentialReconciliationBegin");
4398
4835
  function parseMlsDevCredentialReconciliationChallenge(value) {
4399
- return boundary7(() => {
4836
+ return boundary9(() => {
4400
4837
  const input = readMlsDataRecord(value, [
4401
4838
  "version",
4402
4839
  "challengeId",
@@ -4409,12 +4846,12 @@ function parseMlsDevCredentialReconciliationChallenge(value) {
4409
4846
  ]);
4410
4847
  const device = parseMlsDevEnrollmentResult({ version: 1, authorization: "registration_only", device: input.device }).device;
4411
4848
  const issuedAtMs = requireMlsInteger(input.issuedAtMs), expiresAtMs = requireMlsInteger(input.expiresAtMs);
4412
- if (issuedAtMs < device.registeredAtMs || expiresAtMs - issuedAtMs !== MLS_DEV_CREDENTIAL_RECONCILIATION_CHALLENGE_TTL_MS) invalid9();
4849
+ if (issuedAtMs < device.registeredAtMs || expiresAtMs - issuedAtMs !== MLS_DEV_CREDENTIAL_RECONCILIATION_CHALLENGE_TTL_MS) invalid12();
4413
4850
  return bounded7({
4414
4851
  version: requireMlsLiteral(input.version, 1),
4415
4852
  challengeId: requireMlsUuid(input.challengeId),
4416
4853
  requestId: requireMlsUuid(input.requestId),
4417
- nonce: encoded5(input.nonce, 32),
4854
+ nonce: encoded6(input.nonce, 32),
4418
4855
  device,
4419
4856
  expectedCredentialGeneration: requireMlsInteger(input.expectedCredentialGeneration),
4420
4857
  issuedAtMs,
@@ -4424,18 +4861,18 @@ function parseMlsDevCredentialReconciliationChallenge(value) {
4424
4861
  }
4425
4862
  __name(parseMlsDevCredentialReconciliationChallenge, "parseMlsDevCredentialReconciliationChallenge");
4426
4863
  function parseMlsDevCredentialReconciliationComplete(value) {
4427
- return boundary7(() => {
4864
+ return boundary9(() => {
4428
4865
  const input = readMlsDataRecord(value, ["version", "challengeId", "proof"]);
4429
- return bounded7({ version: requireMlsLiteral(input.version, 1), challengeId: requireMlsUuid(input.challengeId), proof: encoded5(input.proof, 64) });
4866
+ return bounded7({ version: requireMlsLiteral(input.version, 1), challengeId: requireMlsUuid(input.challengeId), proof: encoded6(input.proof, 64) });
4430
4867
  });
4431
4868
  }
4432
4869
  __name(parseMlsDevCredentialReconciliationComplete, "parseMlsDevCredentialReconciliationComplete");
4433
4870
  function parseMlsDevCredentialReconciliationReceipt(value) {
4434
- return boundary7(() => {
4871
+ return boundary9(() => {
4435
4872
  const input = readMlsDataRecord(value, ["version", "authorization", "challenge", "observedCredentialGeneration", "observedAtMs"]);
4436
4873
  const challenge = parseMlsDevCredentialReconciliationChallenge(input.challenge);
4437
4874
  const observedCredentialGeneration = requireMlsInteger(input.observedCredentialGeneration), observedAtMs = requireMlsInteger(input.observedAtMs);
4438
- if (observedCredentialGeneration < challenge.expectedCredentialGeneration || observedAtMs < challenge.issuedAtMs || observedAtMs >= challenge.expiresAtMs) invalid9();
4875
+ if (observedCredentialGeneration < challenge.expectedCredentialGeneration || observedAtMs < challenge.issuedAtMs || observedAtMs >= challenge.expiresAtMs) invalid12();
4439
4876
  return bounded7({
4440
4877
  version: requireMlsLiteral(input.version, 1),
4441
4878
  authorization: requireMlsLiteral(input.authorization, "credential_generation_observation_only"),
@@ -4461,51 +4898,51 @@ var MlsDevDeviceCustodyValidationError = class extends Error {
4461
4898
  this.name = "MlsDevDeviceCustodyValidationError";
4462
4899
  }
4463
4900
  };
4464
- var utf86 = new TextEncoder();
4465
- function invalid10() {
4901
+ var utf87 = new TextEncoder();
4902
+ function invalid13() {
4466
4903
  throw new MlsDevDeviceCustodyValidationError();
4467
4904
  }
4468
- __name(invalid10, "invalid");
4469
- function boundary8(read) {
4905
+ __name(invalid13, "invalid");
4906
+ function boundary10(read) {
4470
4907
  try {
4471
4908
  return read();
4472
4909
  } catch {
4473
- return invalid10();
4910
+ return invalid13();
4474
4911
  }
4475
4912
  }
4476
- __name(boundary8, "boundary");
4477
- function bounded8(value, limit) {
4478
- if (utf86.encode(JSON.stringify(value)).length > limit) invalid10();
4913
+ __name(boundary10, "boundary");
4914
+ function bounded8(value, limit2) {
4915
+ if (utf87.encode(JSON.stringify(value)).length > limit2) invalid13();
4479
4916
  return Object.freeze(value);
4480
4917
  }
4481
4918
  __name(bounded8, "bounded");
4482
4919
  function binding2(input) {
4483
4920
  return {
4484
4921
  version: requireMlsLiteral(input.version, 1),
4485
- environmentId: requireMlsLiteral(input.environmentId, "canon-dev-v1"),
4922
+ environmentId: requireMlsEnvironmentId(input.environmentId),
4486
4923
  principal: parseMlsDevEnrollmentPrincipal(input.principal),
4487
4924
  installationId: parseMlsDevInstallationId(input.installationId)
4488
4925
  };
4489
4926
  }
4490
4927
  __name(binding2, "binding");
4491
4928
  function parseMlsDevDeviceBinding(value) {
4492
- return boundary8(() => bounded8(binding2(readMlsDataRecord(value, ["version", "environmentId", "principal", "installationId"])), MLS_DEV_DEVICE_CONTEXT_MAX_BYTES));
4929
+ return boundary10(() => bounded8(binding2(readMlsDataRecord(value, ["version", "environmentId", "principal", "installationId"])), MLS_DEV_DEVICE_CONTEXT_MAX_BYTES));
4493
4930
  }
4494
4931
  __name(parseMlsDevDeviceBinding, "parseMlsDevDeviceBinding");
4495
4932
  function parseMlsDevDeviceContext(value) {
4496
- return boundary8(() => {
4933
+ return boundary10(() => {
4497
4934
  const input = readMlsDataRecord(value, ["version", "environmentId", "principal", "installationId", "revision"]);
4498
4935
  const revision2 = requireMlsInteger(input.revision);
4499
- if (revision2 >= Number.MAX_SAFE_INTEGER) invalid10();
4936
+ if (revision2 >= Number.MAX_SAFE_INTEGER) invalid13();
4500
4937
  return bounded8({ ...binding2(input), revision: revision2 }, MLS_DEV_DEVICE_CONTEXT_MAX_BYTES);
4501
4938
  });
4502
4939
  }
4503
4940
  __name(parseMlsDevDeviceContext, "parseMlsDevDeviceContext");
4504
4941
  function parseMlsDevDeviceCommand(value) {
4505
- return boundary8(() => {
4506
- if (value === null || typeof value !== "object") invalid10();
4942
+ return boundary10(() => {
4943
+ if (value === null || typeof value !== "object") invalid13();
4507
4944
  const descriptor = Object.getOwnPropertyDescriptor(value, "op");
4508
- if (!descriptor || !Object.hasOwn(descriptor, "value")) invalid10();
4945
+ if (!descriptor || !Object.hasOwn(descriptor, "value")) invalid13();
4509
4946
  if (descriptor.value === "create") {
4510
4947
  const input2 = readMlsDataRecord(value, ["op"]);
4511
4948
  return Object.freeze({ op: requireMlsLiteral(input2.op, "create") });
@@ -4521,19 +4958,19 @@ function parseMlsDevDeviceCommand(value) {
4521
4958
  const input2 = readMlsDataRecord(value, ["op", "challenge", "expectedCredentialGeneration"]);
4522
4959
  const challenge2 = parseMlsDevCredentialReconciliationChallenge(input2.challenge);
4523
4960
  const expectedCredentialGeneration2 = requireMlsInteger(input2.expectedCredentialGeneration);
4524
- if (challenge2.expectedCredentialGeneration !== expectedCredentialGeneration2) invalid10();
4961
+ if (challenge2.expectedCredentialGeneration !== expectedCredentialGeneration2) invalid13();
4525
4962
  return bounded8({
4526
4963
  op: requireMlsLiteral(input2.op, "credential_reconciliation_proof"),
4527
4964
  challenge: challenge2,
4528
4965
  expectedCredentialGeneration: expectedCredentialGeneration2
4529
4966
  }, MLS_DEV_DEVICE_COMMAND_MAX_BYTES);
4530
4967
  }
4531
- if (descriptor.value !== "credential_proof") invalid10();
4968
+ if (descriptor.value !== "credential_proof") invalid13();
4532
4969
  const input = readMlsDataRecord(value, ["op", "challenge", "registrationResult", "expectedCredentialGeneration"]);
4533
4970
  const challenge = parseMlsDevCredentialChallenge(input.challenge);
4534
4971
  const registrationResult = parseMlsDevEnrollmentResult(input.registrationResult);
4535
4972
  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();
4973
+ if (expectedCredentialGeneration >= Number.MAX_SAFE_INTEGER || challenge.credential.claims.generation !== expectedCredentialGeneration + 1 || JSON.stringify(challenge.credential.claims.device) !== JSON.stringify(registrationResult.device)) invalid13();
4537
4974
  return bounded8({
4538
4975
  op: requireMlsLiteral(input.op, "credential_proof"),
4539
4976
  challenge,
@@ -4543,29 +4980,29 @@ function parseMlsDevDeviceCommand(value) {
4543
4980
  });
4544
4981
  }
4545
4982
  __name(parseMlsDevDeviceCommand, "parseMlsDevDeviceCommand");
4546
- function encoded6(value, bytes) {
4983
+ function encoded7(value, bytes) {
4547
4984
  decodeCanonicalMlsBase64Url(value, bytes);
4548
4985
  return value;
4549
4986
  }
4550
- __name(encoded6, "encoded");
4987
+ __name(encoded7, "encoded");
4551
4988
  function wrapped(value) {
4552
- if (typeof value !== "string" || value.length > MLS_DEV_DEVICE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid10();
4989
+ if (typeof value !== "string" || value.length > MLS_DEV_DEVICE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid13();
4553
4990
  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();
4991
+ 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
4992
  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();
4993
+ if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0) invalid13();
4994
+ if (!body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0) invalid13();
4558
4995
  return value;
4559
4996
  }
4560
4997
  __name(wrapped, "wrapped");
4561
4998
  function parseMlsDevDevicePreparation(value, op) {
4562
- return boundary8(() => {
4563
- if (!["create", "enrollment_proof", "credential_proof", "credential_reconciliation_proof"].includes(op)) invalid10();
4999
+ return boundary10(() => {
5000
+ if (!["create", "enrollment_proof", "credential_proof", "credential_reconciliation_proof"].includes(op)) invalid13();
4564
5001
  const input = readMlsDataRecord(value, ["wrappedState", "payload"]);
4565
5002
  const payload = readMlsDataRecord(input.payload, op === "create" ? ["signaturePublicKey"] : ["signaturePublicKey", "proof"]);
4566
5003
  return bounded8({ wrappedState: wrapped(input.wrappedState), payload: Object.freeze({
4567
- signaturePublicKey: encoded6(payload.signaturePublicKey, 32),
4568
- ...op === "create" ? {} : { proof: encoded6(payload.proof, 64) }
5004
+ signaturePublicKey: encoded7(payload.signaturePublicKey, 32),
5005
+ ...op === "create" ? {} : { proof: encoded7(payload.proof, 64) }
4569
5006
  }) }, MLS_DEV_DEVICE_COMMAND_MAX_BYTES);
4570
5007
  });
4571
5008
  }
@@ -4586,56 +5023,56 @@ var MlsDevKeyPackageValidationError = class extends Error {
4586
5023
  this.name = "MlsDevKeyPackageValidationError";
4587
5024
  }
4588
5025
  };
4589
- var utf87 = new TextEncoder();
4590
- function invalid11() {
5026
+ var utf88 = new TextEncoder();
5027
+ function invalid14() {
4591
5028
  throw new MlsDevKeyPackageValidationError();
4592
5029
  }
4593
- __name(invalid11, "invalid");
4594
- function boundary9(read) {
5030
+ __name(invalid14, "invalid");
5031
+ function boundary11(read) {
4595
5032
  try {
4596
5033
  return read();
4597
5034
  } catch {
4598
- return invalid11();
5035
+ return invalid14();
4599
5036
  }
4600
5037
  }
4601
- __name(boundary9, "boundary");
5038
+ __name(boundary11, "boundary");
4602
5039
  function bounded9(value, maximum) {
4603
- if (utf87.encode(JSON.stringify(value)).length > maximum) invalid11();
5040
+ if (utf88.encode(JSON.stringify(value)).length > maximum) invalid14();
4604
5041
  return Object.freeze(value);
4605
5042
  }
4606
5043
  __name(bounded9, "bounded");
4607
- function encoded7(value, bytes) {
5044
+ function encoded8(value, bytes) {
4608
5045
  decodeCanonicalMlsBase64Url(value, bytes);
4609
5046
  return value;
4610
5047
  }
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();
5048
+ __name(encoded8, "encoded");
5049
+ function wire3(value) {
5050
+ if (typeof value !== "string" || value.length < 2 || value.length > Math.ceil(MLS_DEV_KEY_PACKAGE_WIRE_MAX_BYTES * 4 / 3)) invalid14();
4614
5051
  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();
5052
+ 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
5053
  const last = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(value.at(-1));
4617
- if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid11();
5054
+ if (value.length % 4 === 2 && (last & 15) !== 0 || value.length % 4 === 3 && (last & 3) !== 0) invalid14();
4618
5055
  return value;
4619
5056
  }
4620
- __name(wire2, "wire");
5057
+ __name(wire3, "wire");
4621
5058
  function wrapped2(value) {
4622
- if (typeof value !== "string" || value.length > MLS_DEV_KEY_PACKAGE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid11();
5059
+ if (typeof value !== "string" || value.length > MLS_DEV_KEY_PACKAGE_WRAPPED_STATE_MAX_BYTES || !value.startsWith("v1:")) invalid14();
4623
5060
  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();
5061
+ 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
5062
  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();
5063
+ if (body.endsWith("==") && (alphabet.indexOf(body.at(-3)) & 15) !== 0) invalid14();
5064
+ if (!body.endsWith("==") && body.endsWith("=") && (alphabet.indexOf(body.at(-2)) & 3) !== 0) invalid14();
4628
5065
  const bytes = body.length / 4 * 3 - (body.endsWith("==") ? 2 : body.endsWith("=") ? 1 : 0);
4629
- if (bytes > 128 * 1024 + 28) invalid11();
5066
+ if (bytes > 128 * 1024 + 28) invalid14();
4630
5067
  return value;
4631
5068
  }
4632
5069
  __name(wrapped2, "wrapped");
4633
5070
  function parseMlsDevKeyPackageId(value) {
4634
- return boundary9(() => requireMlsUuid(value));
5071
+ return boundary11(() => requireMlsUuid(value));
4635
5072
  }
4636
5073
  __name(parseMlsDevKeyPackageId, "parseMlsDevKeyPackageId");
4637
5074
  function parseMlsDevKeyPackageCommand(value) {
4638
- return boundary9(() => {
5075
+ return boundary11(() => {
4639
5076
  const input = readMlsDataRecord(value, ["version", "op", "keyPackageId", "credential"]);
4640
5077
  const token2 = parseMlsDevCredentialToken(input.credential);
4641
5078
  parseMlsDevEnrollmentPrincipal(token2.unsigned.claims.device.principal);
@@ -4649,7 +5086,7 @@ function parseMlsDevKeyPackageCommand(value) {
4649
5086
  }
4650
5087
  __name(parseMlsDevKeyPackageCommand, "parseMlsDevKeyPackageCommand");
4651
5088
  function parseMlsDevKeyPackagePayload(value) {
4652
- return boundary9(() => {
5089
+ return boundary11(() => {
4653
5090
  const input = readMlsDataRecord(value, [
4654
5091
  "version",
4655
5092
  "keyPackageId",
@@ -4664,7 +5101,7 @@ function parseMlsDevKeyPackagePayload(value) {
4664
5101
  "expiresAtMs"
4665
5102
  ]);
4666
5103
  const notBeforeMs = requireMlsInteger(input.notBeforeMs), expiresAtMs = requireMlsInteger(input.expiresAtMs);
4667
- if (notBeforeMs % 1e3 !== 0 || expiresAtMs % 1e3 !== 0 || expiresAtMs <= notBeforeMs || expiresAtMs - notBeforeMs > 864e5) invalid11();
5104
+ if (notBeforeMs % 1e3 !== 0 || expiresAtMs % 1e3 !== 0 || expiresAtMs <= notBeforeMs || expiresAtMs - notBeforeMs > 864e5) invalid14();
4668
5105
  return bounded9({
4669
5106
  version: requireMlsLiteral(input.version, 1),
4670
5107
  keyPackageId: requireMlsUuid(input.keyPackageId),
@@ -4672,9 +5109,9 @@ function parseMlsDevKeyPackagePayload(value) {
4672
5109
  credentialId: requireMlsUuid(input.credentialId),
4673
5110
  credentialGeneration: requireMlsInteger(input.credentialGeneration, 1),
4674
5111
  ciphersuite: requireMlsLiteral(input.ciphersuite, 1),
4675
- signaturePublicKey: encoded7(input.signaturePublicKey, 32),
4676
- keyPackage: wire2(input.keyPackage),
4677
- keyPackageRef: encoded7(input.keyPackageRef, 32),
5112
+ signaturePublicKey: encoded8(input.signaturePublicKey, 32),
5113
+ keyPackage: wire3(input.keyPackage),
5114
+ keyPackageRef: encoded8(input.keyPackageRef, 32),
4678
5115
  notBeforeMs,
4679
5116
  expiresAtMs
4680
5117
  }, MLS_DEV_KEY_PACKAGE_PREPARATION_MAX_BYTES);
@@ -4682,7 +5119,7 @@ function parseMlsDevKeyPackagePayload(value) {
4682
5119
  }
4683
5120
  __name(parseMlsDevKeyPackagePayload, "parseMlsDevKeyPackagePayload");
4684
5121
  function parseMlsDevKeyPackagePreparation(value) {
4685
- return boundary9(() => {
5122
+ return boundary11(() => {
4686
5123
  const input = readMlsDataRecord(value, ["wrappedState", "payload"]);
4687
5124
  return bounded9(
4688
5125
  { wrappedState: wrapped2(input.wrappedState), payload: parseMlsDevKeyPackagePayload(input.payload) },
@@ -4692,6 +5129,74 @@ function parseMlsDevKeyPackagePreparation(value) {
4692
5129
  }
4693
5130
  __name(parseMlsDevKeyPackagePreparation, "parseMlsDevKeyPackagePreparation");
4694
5131
 
5132
+ // ../backend-contracts/src/mlsPrincipalAlias.ts
5133
+ var MLS_PRINCIPAL_ALIAS_PREFIX = "mlsa_";
5134
+ var ALIAS_PATTERN = /^mlsa_[A-Za-z0-9_-]{43}$/;
5135
+ var utf89 = new TextEncoder();
5136
+ var domain3 = utf89.encode("canon.mls.principal-alias.v1\0");
5137
+ function invalid15() {
5138
+ throw new Error("INVALID_MLS_PRINCIPAL_ALIAS");
5139
+ }
5140
+ __name(invalid15, "invalid");
5141
+ function isMlsPrincipalAlias(value) {
5142
+ return typeof value === "string" && ALIAS_PATTERN.test(value);
5143
+ }
5144
+ __name(isMlsPrincipalAlias, "isMlsPrincipalAlias");
5145
+ function isMlsAccountId(value) {
5146
+ return isMlsPrincipalId(value) && !value.includes("/") && value !== "." && value !== "..";
5147
+ }
5148
+ __name(isMlsAccountId, "isMlsAccountId");
5149
+ function accountId(value) {
5150
+ if (!isMlsAccountId(value) || ALIAS_PATTERN.test(value)) invalid15();
5151
+ return value;
5152
+ }
5153
+ __name(accountId, "accountId");
5154
+ function parseMlsPrincipalOpening(value) {
5155
+ try {
5156
+ const input = readMlsDataRecord(value, ["type", "accountId", "salt"]);
5157
+ if (input.type !== "human" && input.type !== "ai_agent") invalid15();
5158
+ decodeCanonicalMlsBase64Url(input.salt, 32);
5159
+ return Object.freeze({ type: input.type, accountId: accountId(input.accountId), salt: input.salt });
5160
+ } catch {
5161
+ return invalid15();
5162
+ }
5163
+ }
5164
+ __name(parseMlsPrincipalOpening, "parseMlsPrincipalOpening");
5165
+ function encodeMlsPrincipalAliasInput(environmentId, opening) {
5166
+ const value = parseMlsPrincipalOpening(opening);
5167
+ const environment = utf89.encode(requireMlsEnvironmentId(environmentId));
5168
+ const id7 = utf89.encode(value.accountId);
5169
+ const output = new Uint8Array(domain3.length + 4 + environment.length + 1 + 4 + id7.length + 32);
5170
+ const view = new DataView(output.buffer);
5171
+ let offset = 0;
5172
+ const raw = /* @__PURE__ */ __name((bytes) => {
5173
+ output.set(bytes, offset);
5174
+ offset += bytes.length;
5175
+ }, "raw");
5176
+ const lp = /* @__PURE__ */ __name((bytes) => {
5177
+ view.setUint32(offset, bytes.length);
5178
+ offset += 4;
5179
+ raw(bytes);
5180
+ }, "lp");
5181
+ raw(domain3);
5182
+ lp(environment);
5183
+ output[offset++] = value.type === "human" ? 0 : 1;
5184
+ lp(id7);
5185
+ raw(decodeCanonicalMlsBase64Url(value.salt, 32));
5186
+ return output;
5187
+ }
5188
+ __name(encodeMlsPrincipalAliasInput, "encodeMlsPrincipalAliasInput");
5189
+ function parseMlsRoomIdentities(value) {
5190
+ if (value === null || typeof value !== "object" || Array.isArray(value)) invalid15();
5191
+ const output = /* @__PURE__ */ Object.create(null);
5192
+ for (const [alias, opening] of Object.entries(readMlsDataRecord(value, Object.keys(value)))) {
5193
+ if (!isMlsPrincipalAlias(alias)) invalid15();
5194
+ output[alias] = parseMlsPrincipalOpening(opening);
5195
+ }
5196
+ return Object.freeze(output);
5197
+ }
5198
+ __name(parseMlsRoomIdentities, "parseMlsRoomIdentities");
5199
+
4695
5200
  // ../endpoint/src/runtime-api-origins.generated.ts
4696
5201
  var RUNTIME_API_ORIGINS = {
4697
5202
  "canon-dev-v1": "https://dev.api.canonmail.com",
@@ -4699,76 +5204,86 @@ var RUNTIME_API_ORIGINS = {
4699
5204
  };
4700
5205
 
4701
5206
  // ../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() {
5207
+ function mlsDevDeviceHttpConfiguration(environmentId) {
5208
+ if (!isMlsEnvironmentId(environmentId)) invalid16();
5209
+ const origin = RUNTIME_API_ORIGINS[environmentId];
5210
+ return Object.freeze({
5211
+ enrollmentUrl: `${origin}/mls/enrollment`,
5212
+ credentialUrl: `${origin}/mls/credential`,
5213
+ reconciliationUrl: `${origin}/mls/reconciliation`,
5214
+ keyPackagesUrl: `${origin}/mls/key-packages`,
5215
+ trustedOrigins: Object.freeze([origin])
5216
+ });
5217
+ }
5218
+ __name(mlsDevDeviceHttpConfiguration, "mlsDevDeviceHttpConfiguration");
5219
+ function invalid16() {
4710
5220
  throw new Error("MLS_DEV_CLIENT_CONFIGURATION_INVALID");
4711
5221
  }
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();
5222
+ __name(invalid16, "invalid");
5223
+ function record4(value, keys2) {
5224
+ if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) invalid16();
5225
+ const fields2 = Object.getOwnPropertyDescriptors(value);
5226
+ if (Reflect.ownKeys(fields2).length !== keys2.length || keys2.some((key) => !Object.hasOwn(fields2, key) || !Object.hasOwn(fields2[key], "value"))) invalid16();
4717
5227
  return value;
4718
5228
  }
4719
- __name(record3, "record");
5229
+ __name(record4, "record");
4720
5230
  function primeOrderPoint(value) {
4721
5231
  const point = ed25519.Point.fromBytes(value, false);
4722
5232
  return !point.isSmallOrder() && point.isTorsionFree();
4723
5233
  }
4724
5234
  __name(primeOrderPoint, "primeOrderPoint");
4725
- function issuerKeys(value) {
4726
- if (!Array.isArray(value) || value.length < 1 || value.length > 8) invalid12();
5235
+ function issuerKeys(value, environmentId, receipt = false) {
5236
+ if (!Array.isArray(value) || value.length < 1 || value.length > 8) invalid16();
4727
5237
  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();
5238
+ let environment = environmentId;
5239
+ return Object.freeze(Array.from(value, (item2) => {
5240
+ const key = record4(item2, ["keyVersion", "signaturePublicKey"]);
5241
+ const keyVersion = receipt ? parseMlsDevReceiptKeyVersion(key.keyVersion, environment) : parseMlsDevIssuerKeyVersion(key.keyVersion, environment);
5242
+ environment ??= receipt ? mlsEnvironmentOfReceiptKeyVersion(keyVersion) : mlsEnvironmentOfIssuerKeyVersion(keyVersion);
5243
+ if (seen.has(keyVersion) || typeof key.signaturePublicKey !== "string" || !primeOrderPoint(decodeCanonicalMlsBase64Url(key.signaturePublicKey, 32))) invalid16();
4732
5244
  seen.add(keyVersion);
4733
- return Object.freeze({ keyVersion, signaturePublicKey: key2.signaturePublicKey });
5245
+ return Object.freeze({ keyVersion, signaturePublicKey: key.signaturePublicKey });
4734
5246
  }));
4735
5247
  }
4736
5248
  __name(issuerKeys, "issuerKeys");
4737
5249
  function parseMlsDevClientConfiguration(value) {
4738
5250
  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();
5251
+ const listed = !!value && typeof value === "object" && Object.hasOwn(value, "principalIds");
5252
+ const input = record4(value, ["version", "environmentId", "enabled", ...listed ? ["principalIds"] : [], "issuerKeys", "receiptKeys"]);
5253
+ if (input.version !== 1 || !isMlsEnvironmentId(input.environmentId) || input.enabled !== true || listed && (!Array.isArray(input.principalIds) || input.principalIds.length < 1 || input.principalIds.length > 100)) invalid16();
5254
+ const environmentId = input.environmentId;
5255
+ const principalIds = listed ? Array.from(input.principalIds, (id7) => parseMlsDevEnrollmentPrincipal({ type: "human", id: id7 }).id) : void 0;
5256
+ if (principalIds && new Set(principalIds).size !== principalIds.length) invalid16();
4743
5257
  return Object.freeze({
4744
5258
  version: 1,
4745
- environmentId: "canon-dev-v1",
5259
+ environmentId,
4746
5260
  enabled: true,
4747
- principalIds: Object.freeze(principalIds),
4748
- issuerKeys: issuerKeys(input.issuerKeys)
5261
+ ...principalIds ? { principalIds: Object.freeze(principalIds) } : {},
5262
+ issuerKeys: issuerKeys(input.issuerKeys, environmentId),
5263
+ receiptKeys: issuerKeys(input.receiptKeys, environmentId, true)
4749
5264
  });
4750
5265
  } catch {
4751
- return invalid12();
5266
+ return invalid16();
4752
5267
  }
4753
5268
  }
4754
5269
  __name(parseMlsDevClientConfiguration, "parseMlsDevClientConfiguration");
4755
5270
  function createMlsDevCredentialVerifier(options) {
4756
5271
  let trusted;
4757
5272
  try {
4758
- trusted = new Map(issuerKeys(options.issuerKeys).map((key2) => [key2.keyVersion, key2.signaturePublicKey]));
5273
+ trusted = new Map(issuerKeys(options.issuerKeys).map((key) => [key.keyVersion, key.signaturePublicKey]));
4759
5274
  } catch {
4760
- return invalid12();
5275
+ return invalid16();
4761
5276
  }
4762
5277
  const clock = options.clock ?? Date.now;
4763
5278
  return async (value) => {
4764
5279
  try {
4765
5280
  const receipt = parseMlsDevCredentialReceipt(value);
4766
5281
  const parsed = parseMlsDevCredentialToken(receipt.credential);
4767
- const key2 = trusted.get(parsed.unsigned.keyVersion);
5282
+ const key = trusted.get(parsed.unsigned.keyVersion);
4768
5283
  const now = clock();
4769
5284
  const { issuedAtMs, expiresAtMs } = parsed.unsigned.claims;
4770
- if (!key2 || !Number.isSafeInteger(now) || now < issuedAtMs || now >= expiresAtMs) return false;
4771
- const publicKey = decodeCanonicalMlsBase64Url(key2, 32);
5285
+ if (!key || !Number.isSafeInteger(now) || now < issuedAtMs || now >= expiresAtMs) return false;
5286
+ const publicKey = decodeCanonicalMlsBase64Url(key, 32);
4772
5287
  const signature = decodeCanonicalMlsBase64Url(parsed.signature, 64);
4773
5288
  if (!primeOrderPoint(publicKey) || !primeOrderPoint(signature.subarray(0, 32))) return false;
4774
5289
  return ed25519.verify(signature, new TextEncoder().encode(parsed.signingInput), publicKey, { zip215: false });
@@ -4782,7 +5297,16 @@ __name(createMlsDevCredentialVerifier, "createMlsDevCredentialVerifier");
4782
5297
  export {
4783
5298
  __name,
4784
5299
  getCanonEnvironmentContract,
5300
+ CANON_CLIENT_HEADER,
5301
+ CLIENT_UPDATE_REQUIRED,
5302
+ isCanonClientVersion,
5303
+ formatCanonClientHeader,
4785
5304
  sanitizeDownloadFileName,
5305
+ describeAttachment,
5306
+ isCanonMediaOrigin,
5307
+ isCanonUploadUrl,
5308
+ resolveAllowedUploadMimeType,
5309
+ isMlsEnvironmentId,
4786
5310
  MLS_DEV_ENROLLMENT_MAX_BYTES,
4787
5311
  parseMlsDevEnrollmentPrincipal,
4788
5312
  parseMlsDevEnrollmentBegin,
@@ -4799,6 +5323,8 @@ export {
4799
5323
  createMlsDevCredentialSigningInput,
4800
5324
  parseMlsDevCredentialToken,
4801
5325
  parseMlsDevCredentialReceipt,
5326
+ MLS_DEV_GROUP_RECEIPT_CLOCK_SKEW,
5327
+ isMlsDevReceiptClockSkew,
4802
5328
  parseMlsDevGroupFeedEntry,
4803
5329
  parseMlsDevGroupFeedQuery,
4804
5330
  parseMlsDevGroupFeedResult,
@@ -4808,23 +5334,36 @@ export {
4808
5334
  parseMlsDevKeyPackagePublicationReceipt,
4809
5335
  parseMlsDevKeyPackageClaim,
4810
5336
  parseMlsDevKeyPackageClaimReceipt,
5337
+ MLS_DEV_INTERACTION_LIMITS,
5338
+ parseMlsDevInteractionRequestBody,
5339
+ parseMlsDevInteractionResponseBody,
5340
+ parseMlsDevInteractionWithdrawBody,
5341
+ parseMlsDevApplicationPayload,
5342
+ assertMlsDevInteractionPayloadBinding,
5343
+ isMlsDevInteractionAnswerAllowed,
4811
5344
  parseMlsDevGroupCreateConversation,
4812
5345
  parseMlsDevGroupHead,
4813
5346
  parseMlsDevGroupMarker,
4814
5347
  parseMlsDevGroupRoster,
5348
+ parseMlsDevRoomRemoval,
4815
5349
  parseMlsDevGroupControl,
4816
5350
  parseMlsDevGroupAcceptedControl,
5351
+ parseMlsDevGroupAdmissionsResult,
4817
5352
  parseMlsDevGroupQuery,
4818
5353
  parseMlsDevGroupQueryResult,
4819
5354
  parseMlsDevGroupContext,
4820
5355
  parseMlsDevGroupCommand,
4821
5356
  parseMlsDevGroupPreparation,
4822
- MLS_DEV_TEXT_PROTOCOL,
5357
+ MLS_DEV_TEXT_PROTOCOL_V3,
5358
+ isMlsDevTextProtocol,
5359
+ mlsDevProtocolCarriesCards,
5360
+ MLS_DEV_REPLY_QUOTE_MAX_CHARACTERS,
5361
+ MLS_DEV_TEXT_MAX_BYTES,
4823
5362
  parseMlsDevApplicationReceipt,
4824
5363
  parseMlsDevTextPayload,
5364
+ parseMlsDevItemPayload,
4825
5365
  encodeMlsDevApplicationEnvelopeHash,
4826
5366
  RUNTIME_CARD_FIELD_TYPES,
4827
- RUNTIME_CARD_LIMITS,
4828
5367
  RUNTIME_CARD_LINE_ITEM_COLUMN_TYPES,
4829
5368
  readMembershipChangeMetadata,
4830
5369
  formatMembershipChangeNotice,
@@ -4850,36 +5389,20 @@ export {
4850
5389
  ENDPOINT_ID_PATTERN,
4851
5390
  ENDPOINT_ACTION_PATTERN,
4852
5391
  isEndpointOperationReceipt,
5392
+ CONNECTOR_RELAY_INSTALLATION_PREFIX,
5393
+ CONNECTOR_RELAY_INSTALLATION_PATTERN,
5394
+ isConnectorRelayInstallation,
5395
+ isConnectorRelayCredential,
5396
+ CONNECTOR_RELAY_MAX_BODY_BYTES,
5397
+ CONNECTOR_RELAY_MAX_RESPONSE_BYTES,
5398
+ CONNECTOR_RELAY_ANSWER_WITHIN_MS,
5399
+ connectorRelayResponseBytes,
5400
+ ConnectorRelayRequestError,
5401
+ parseConnectorRelayRequest,
4853
5402
  mergeDeliveryObservation,
4854
5403
  projectDeliveryStatus,
4855
5404
  classifyTransferHttpFailure,
4856
5405
  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
5406
  MLS_DEV_CREDENTIAL_RECONCILIATION_MAX_BYTES,
4884
5407
  parseMlsDevCredentialReconciliationBegin,
4885
5408
  parseMlsDevCredentialReconciliationChallenge,
@@ -4893,7 +5416,12 @@ export {
4893
5416
  parseMlsDevKeyPackageCommand,
4894
5417
  parseMlsDevKeyPackagePayload,
4895
5418
  parseMlsDevKeyPackagePreparation,
4896
- MLS_DEV_DEVICE_HTTP_CONFIGURATION,
5419
+ MLS_PRINCIPAL_ALIAS_PREFIX,
5420
+ isMlsPrincipalAlias,
5421
+ parseMlsPrincipalOpening,
5422
+ encodeMlsPrincipalAliasInput,
5423
+ parseMlsRoomIdentities,
5424
+ mlsDevDeviceHttpConfiguration,
4897
5425
  parseMlsDevClientConfiguration,
4898
5426
  createMlsDevCredentialVerifier
4899
5427
  };