@jini-ai/cms 0.3.4 → 0.3.6

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 (104) hide show
  1. package/README.md +22 -17
  2. package/dist/content-types/agent-tools.d.ts.map +1 -1
  3. package/dist/content-types/agent-tools.js +1 -1
  4. package/dist/content-types/agent-tools.js.map +1 -1
  5. package/dist/content-types/errors.d.ts +19 -1
  6. package/dist/content-types/errors.d.ts.map +1 -1
  7. package/dist/content-types/errors.js +22 -1
  8. package/dist/content-types/errors.js.map +1 -1
  9. package/dist/content-types/index-provisioning.d.ts +56 -10
  10. package/dist/content-types/index-provisioning.d.ts.map +1 -1
  11. package/dist/content-types/index-provisioning.js +86 -13
  12. package/dist/content-types/index-provisioning.js.map +1 -1
  13. package/dist/content-types/index.d.ts +15 -3
  14. package/dist/content-types/index.d.ts.map +1 -1
  15. package/dist/content-types/index.js +14 -2
  16. package/dist/content-types/index.js.map +1 -1
  17. package/dist/content-types/lifecycle.js +3 -3
  18. package/dist/content-types/lifecycle.js.map +1 -1
  19. package/dist/content-types/types.d.ts +64 -3
  20. package/dist/content-types/types.d.ts.map +1 -1
  21. package/dist/content-types/types.js +67 -3
  22. package/dist/content-types/types.js.map +1 -1
  23. package/dist/content-types/write-service.d.ts +18 -3
  24. package/dist/content-types/write-service.d.ts.map +1 -1
  25. package/dist/content-types/write-service.js +28 -2
  26. package/dist/content-types/write-service.js.map +1 -1
  27. package/dist/core/ports.d.ts +12 -2
  28. package/dist/core/ports.d.ts.map +1 -1
  29. package/dist/entries/field-validation.d.ts.map +1 -1
  30. package/dist/entries/field-validation.js +96 -1
  31. package/dist/entries/field-validation.js.map +1 -1
  32. package/dist/entries/write-service.d.ts +14 -0
  33. package/dist/entries/write-service.d.ts.map +1 -1
  34. package/dist/entries/write-service.js +2 -2
  35. package/dist/entries/write-service.js.map +1 -1
  36. package/dist/identity/admin-crud-service.d.ts +28 -0
  37. package/dist/identity/admin-crud-service.d.ts.map +1 -1
  38. package/dist/identity/admin-crud-service.js +30 -0
  39. package/dist/identity/admin-crud-service.js.map +1 -1
  40. package/dist/identity/auth-service.d.ts +32 -1
  41. package/dist/identity/auth-service.d.ts.map +1 -1
  42. package/dist/identity/auth-service.js +44 -15
  43. package/dist/identity/auth-service.js.map +1 -1
  44. package/dist/identity/index.d.ts +4 -1
  45. package/dist/identity/index.d.ts.map +1 -1
  46. package/dist/identity/index.js +4 -1
  47. package/dist/identity/index.js.map +1 -1
  48. package/dist/identity/seed.d.ts +14 -2
  49. package/dist/identity/seed.d.ts.map +1 -1
  50. package/dist/identity/seed.js +197 -45
  51. package/dist/identity/seed.js.map +1 -1
  52. package/dist/media/blob-store.fs.d.ts +7 -0
  53. package/dist/media/blob-store.fs.d.ts.map +1 -1
  54. package/dist/media/blob-store.fs.js +12 -2
  55. package/dist/media/blob-store.fs.js.map +1 -1
  56. package/dist/media/content-type-sniffer.d.ts +1 -1
  57. package/dist/media/content-type-sniffer.d.ts.map +1 -1
  58. package/dist/media/content-type-sniffer.js +52 -4
  59. package/dist/media/content-type-sniffer.js.map +1 -1
  60. package/dist/media/html-attributes.d.ts +90 -0
  61. package/dist/media/html-attributes.d.ts.map +1 -0
  62. package/dist/media/html-attributes.js +161 -0
  63. package/dist/media/html-attributes.js.map +1 -0
  64. package/dist/media/image-transformer.sharp.d.ts +35 -1
  65. package/dist/media/image-transformer.sharp.d.ts.map +1 -1
  66. package/dist/media/image-transformer.sharp.js +44 -2
  67. package/dist/media/image-transformer.sharp.js.map +1 -1
  68. package/dist/media/index.d.ts +2 -1
  69. package/dist/media/index.d.ts.map +1 -1
  70. package/dist/media/index.js +2 -1
  71. package/dist/media/index.js.map +1 -1
  72. package/dist/media/media-service.d.ts +93 -1
  73. package/dist/media/media-service.d.ts.map +1 -1
  74. package/dist/media/media-service.js +254 -7
  75. package/dist/media/media-service.js.map +1 -1
  76. package/dist/media/ports.d.ts +8 -1
  77. package/dist/media/ports.d.ts.map +1 -1
  78. package/dist/media/rendition-service.d.ts +7 -1
  79. package/dist/media/rendition-service.d.ts.map +1 -1
  80. package/dist/media/rendition-service.js +10 -4
  81. package/dist/media/rendition-service.js.map +1 -1
  82. package/dist/media/repo.memory.d.ts +4 -0
  83. package/dist/media/repo.memory.d.ts.map +1 -1
  84. package/dist/media/repo.memory.js +3 -0
  85. package/dist/media/repo.memory.js.map +1 -1
  86. package/dist/media/tool-registrations.d.ts +6 -2
  87. package/dist/media/tool-registrations.d.ts.map +1 -1
  88. package/dist/media/tool-registrations.js +19 -2
  89. package/dist/media/tool-registrations.js.map +1 -1
  90. package/dist/media/types.d.ts +26 -0
  91. package/dist/media/types.d.ts.map +1 -1
  92. package/dist/media/types.js.map +1 -1
  93. package/dist/navigation/agent-tools.d.ts.map +1 -1
  94. package/dist/navigation/agent-tools.js +8 -1
  95. package/dist/navigation/agent-tools.js.map +1 -1
  96. package/dist/navigation/index.d.ts +10 -1
  97. package/dist/navigation/index.d.ts.map +1 -1
  98. package/dist/navigation/index.js +10 -1
  99. package/dist/navigation/index.js.map +1 -1
  100. package/dist/navigation/menu-service.d.ts +60 -4
  101. package/dist/navigation/menu-service.d.ts.map +1 -1
  102. package/dist/navigation/menu-service.js +106 -8
  103. package/dist/navigation/menu-service.js.map +1 -1
  104. package/package.json +1 -1
@@ -23,6 +23,16 @@ import { normalizeUsername } from "./username.js";
23
23
  */
24
24
  /** REQ-09: the literal id the legacy Article VI actor stamp resolves to. */
25
25
  const LEGACY_USER_LOCAL_PRINCIPAL_ID = "user-local";
26
+ /**
27
+ * The built-in role the seeded owner user holds, and its authority. Named constants because two
28
+ * call sites now depend on them agreeing exactly — the fresh seed below and `ensureOwnerRoleBinding`,
29
+ * which repairs an interrupted one. Drift between the two would be a silent authority bug.
30
+ *
31
+ * REQ-04/REQ-09: the owner policy holds the wildcard `*`, not an enumerated list, so it
32
+ * automatically covers permissions features register later.
33
+ */
34
+ const OWNER_ROLE_NAME = "owner";
35
+ const OWNER_ROLE_PERMISSIONS = ["*"];
26
36
  const BUILTIN_ADMIN_PERMISSIONS = [
27
37
  "content.read",
28
38
  "content.write",
@@ -136,22 +146,77 @@ const BUILTIN_EDITOR_PERMISSIONS = [
136
146
  "theme.set",
137
147
  ];
138
148
  const BUILTIN_VIEWER_PERMISSIONS = ["content.read", "changeset.read", "plugin.read"];
139
- /** Builds one built-in role + its 1:1 policy + policy_permissions rows, and saves all three. */
140
- async function seedBuiltinRoleWithPolicy(required) {
141
- const { deps, workspaceId, name, permissions, nowIso } = required;
142
- const roleId = deps.idGen.newId();
143
- const policyId = deps.idGen.newId();
144
- await deps.repos.roles.save({ id: roleId, workspaceId, name, isBuiltin: true });
145
- await deps.repos.policies.save({
146
- id: policyId,
147
- workspaceId,
148
- name: `${name}-builtin-policy`,
149
- description: `Built-in policy for the seeded '${name}' role.`,
150
- isBuiltin: true,
151
- isFrozen: false,
152
- });
153
- await deps.repos.rolePolicies.save({ id: deps.idGen.newId(), workspaceId, roleId, policyId });
149
+ /**
150
+ * Why every step below is "find, then save only what is missing" rather than a straight insert.
151
+ *
152
+ * This function's writes are NOT transactional and its caller is not awaited by its hosts (Tovu
153
+ * hands `seedIdentity`'s promise back as `RouteDeps.identityReady` and returns synchronously), so
154
+ * a process that exits before the seed finishes — a fast-failing CLI command, a Ctrl-C, a crash —
155
+ * leaves the workspace half-seeded. `seedIdentity`'s own early-return guard keys on the OWNER USER,
156
+ * which is written last, so the next boot correctly decides the seed is unfinished and replays it.
157
+ * A replay that blindly re-inserted would hit `UNIQUE(workspace_id, name)` on `roles`/`policies`
158
+ * (crashing every subsequent boot, permanently), and would silently duplicate `role_policies` /
159
+ * `policy_permissions` rows, which carry no unique index at all. So the replay must converge onto
160
+ * the rows already there instead of re-creating them.
161
+ *
162
+ * What this deliberately does NOT do: adopt a role or policy an operator created themselves. A
163
+ * same-named non-built-in row is a genuine conflict, not a partial seed, and silently promoting it
164
+ * would hand its holders the built-in policy's permissions. Those cases throw.
165
+ */
166
+ /** The built-in role for `name`, reusing a prior (possibly interrupted) seed's row if present. */
167
+ async function ensureBuiltinRole(required) {
168
+ const { deps, workspaceId, name } = required;
169
+ const existing = await deps.repos.roles.findByName({ workspaceId, name });
170
+ if (!existing) {
171
+ const roleId = deps.idGen.newId();
172
+ await deps.repos.roles.save({ id: roleId, workspaceId, name, isBuiltin: true });
173
+ return roleId;
174
+ }
175
+ if (!existing.isBuiltin) {
176
+ throw new Error(`seedIdentity: a non-built-in role named '${name}' already exists in workspace ${workspaceId}. ` +
177
+ `Refusing to adopt it as the built-in '${name}' role — rename or remove it first.`);
178
+ }
179
+ return existing.id;
180
+ }
181
+ /** The built-in policy for `name`, reusing a prior (possibly interrupted) seed's row if present. */
182
+ async function ensureBuiltinPolicy(required) {
183
+ const { deps, workspaceId, name } = required;
184
+ const policyName = `${name}-builtin-policy`;
185
+ const existing = await deps.repos.policies.findByName({ workspaceId, name: policyName });
186
+ if (!existing) {
187
+ const policyId = deps.idGen.newId();
188
+ await deps.repos.policies.save({
189
+ id: policyId,
190
+ workspaceId,
191
+ name: policyName,
192
+ description: `Built-in policy for the seeded '${name}' role.`,
193
+ isBuiltin: true,
194
+ isFrozen: false,
195
+ });
196
+ return policyId;
197
+ }
198
+ if (!existing.isBuiltin) {
199
+ throw new Error(`seedIdentity: a non-built-in policy named '${policyName}' already exists in workspace ${workspaceId}. ` +
200
+ `Refusing to adopt it as the built-in '${name}' policy — rename or remove it first.`);
201
+ }
202
+ return existing.id;
203
+ }
204
+ /**
205
+ * Grant `permissions` to `policyId`, skipping any the policy already holds.
206
+ *
207
+ * Additive by design, and the reason a resumed seed still CONVERGES rather than merely staying
208
+ * quiet: a built-in policy whose permission rows never landed (the interrupt fell between the
209
+ * policy insert and this loop) gains them on the next boot. Compares only unscoped rows because
210
+ * that is the only shape this seed writes — a `resourceType`-scoped row of the same name is a
211
+ * different grant and must not satisfy an unscoped one.
212
+ */
213
+ async function ensurePolicyPermissions(required) {
214
+ const { deps, workspaceId, policyId, permissions } = required;
215
+ const existing = await deps.repos.policyPermissions.listByPolicyId({ workspaceId, policyId });
216
+ const held = new Set(existing.filter((row) => row.resourceType === null).map((row) => row.permission));
154
217
  for (const permission of permissions) {
218
+ if (held.has(permission))
219
+ continue;
155
220
  await deps.repos.policyPermissions.save({
156
221
  id: deps.idGen.newId(),
157
222
  workspaceId,
@@ -161,12 +226,84 @@ async function seedBuiltinRoleWithPolicy(required) {
161
226
  constraintJson: null,
162
227
  });
163
228
  }
229
+ }
230
+ /** Builds one built-in role + its 1:1 policy + policy_permissions rows, converging on what exists. */
231
+ async function seedBuiltinRoleWithPolicy(required) {
232
+ const { deps, workspaceId, name, permissions, nowIso } = required;
233
+ const roleId = await ensureBuiltinRole({ deps, workspaceId, name });
234
+ const policyId = await ensureBuiltinPolicy({ deps, workspaceId, name });
235
+ // `role_policies` has no unique index, so a replay would otherwise stack a second identical link.
236
+ const links = await deps.repos.rolePolicies.listByRoleId({ workspaceId, roleId });
237
+ if (!links.some((link) => link.policyId === policyId)) {
238
+ await deps.repos.rolePolicies.save({ id: deps.idGen.newId(), workspaceId, roleId, policyId });
239
+ }
240
+ await ensurePolicyPermissions({ deps, workspaceId, policyId, permissions });
164
241
  void nowIso; // reserved for a future createdAt column on roles/policies
165
242
  return { roleId, policyId };
166
243
  }
167
244
  /**
168
- * Seed first-boot identity data (idempotent — a no-op if the owner username
169
- * already exists in the workspace).
245
+ * Repair the one completion step `seedIdentity`'s owner-user guard cannot see.
246
+ *
247
+ * The guard keys on the owner USER, and the owner's `principal_roles` link is written after it. A
248
+ * process that exits between those two adjacent writes leaves a workspace whose owner exists, can
249
+ * still log in, and holds no role — and `resolveEffectivePermissions` (`authorize.ts`) starts from
250
+ * `principal_roles` + `principal_policies`, so with neither present EVERY permission evaluates to
251
+ * `no_grant`. Without this step the guard early-returns on the user it finds forever and the site
252
+ * stays bricked for its owner, silently. Neither host-side reconciler closes it either: Tovu's
253
+ * `migrateDeprecatedPermissionGrants` and `applyBuiltinRoleGrants` are handed policy and role repos
254
+ * only, never `principalRoles`, so neither can write a principal->role link at all.
255
+ *
256
+ * Why the gate is "holds NO role" rather than "lacks the owner role". Those two conditions differ
257
+ * on exactly one workspace shape, and it matters: an operator who moves the seeded owner principal
258
+ * to a lesser role leaves it lacking the owner link on purpose. Repairing on that broader signal
259
+ * would re-escalate the principal to wildcard authority on the next restart — a privilege
260
+ * escalation shipped as a bug fix. A principal holding no role at all is never a deliberate state;
261
+ * it is only ever the interrupted seed, so that is what this repairs.
262
+ *
263
+ * Converges rather than assuming: it goes through `seedBuiltinRoleWithPolicy`, so a workspace whose
264
+ * owner ROLE or wildcard grant also never landed gains those here instead of being linked to a role
265
+ * that grants nothing. `principal_roles` carries no unique index, hence the read-before-write.
266
+ *
267
+ * @complexity O(1) — a handful of point reads on a healthy boot (one `listByPrincipalId`, which
268
+ * returns early), plus the fixed converge pass for the owner role only when the repair fires.
269
+ */
270
+ async function ensureOwnerRoleBinding(required) {
271
+ const { deps, workspaceId, ownerPrincipalId, nowIso } = required;
272
+ const heldRoles = await deps.repos.principalRoles.listByPrincipalId({
273
+ workspaceId,
274
+ principalId: ownerPrincipalId,
275
+ });
276
+ if (heldRoles.length > 0)
277
+ return;
278
+ const { roleId } = await seedBuiltinRoleWithPolicy({
279
+ deps,
280
+ workspaceId,
281
+ name: OWNER_ROLE_NAME,
282
+ permissions: OWNER_ROLE_PERMISSIONS,
283
+ nowIso,
284
+ });
285
+ await deps.repos.principalRoles.save({
286
+ id: deps.idGen.newId(),
287
+ workspaceId,
288
+ principalId: ownerPrincipalId,
289
+ roleId,
290
+ });
291
+ }
292
+ /**
293
+ * Seed first-boot identity data.
294
+ *
295
+ * Idempotent in two distinct senses, and both are load-bearing:
296
+ * - A seed that RAN TO COMPLETION is a no-op — the owner-username lookup below early-returns after
297
+ * a single confirming read (`ensureOwnerRoleBinding`) and writes nothing. (This path does not
298
+ * reconcile a built-in policy whose permission list has since grown; that is the host's job — see
299
+ * Tovu's `applyBuiltinRoleGrants` / `migrateDeprecatedPermissionGrants`, chained onto
300
+ * `identityReady`.)
301
+ * - "Ran to completion" is judged on the owner user AND its role link, not the user alone. The link
302
+ * is the seed's last write, so the user is not on its own evidence the seed finished — see
303
+ * `ensureOwnerRoleBinding` for what an interrupt between those two writes costs.
304
+ * - A seed that was INTERRUPTED is resumed, not replayed: every step converges onto the rows a
305
+ * previous attempt already wrote and fills in only what is missing. See the block comment above
306
+ * `ensureBuiltinRole` for why this function must survive being killed halfway.
170
307
  *
171
308
  * @complexity O(1) — fixed small number of inserts (4 roles/policies, ~2
172
309
  * dozen policy_permissions, 3 principals, 1 user, 1 role assignment).
@@ -183,21 +320,35 @@ export async function seedIdentity(required) {
183
320
  username: ownerUsername,
184
321
  });
185
322
  if (existingOwnerUser) {
323
+ // The owner user alone is NOT proof the seed finished — its role link is written after it. See
324
+ // `ensureOwnerRoleBinding`: on a healthy workspace this is one read and no write.
325
+ await ensureOwnerRoleBinding({
326
+ deps,
327
+ workspaceId,
328
+ ownerPrincipalId: existingOwnerUser.principalId,
329
+ nowIso,
330
+ });
186
331
  const existingSystem = (await deps.repos.principals.list({ workspaceId })).find((row) => row.kind === "system" && row.id !== LEGACY_USER_LOCAL_PRINCIPAL_ID);
187
332
  return {
188
333
  ownerPrincipalId: existingOwnerUser.principalId,
189
334
  systemPrincipalId: existingSystem?.id ?? LEGACY_USER_LOCAL_PRINCIPAL_ID,
190
335
  };
191
336
  }
192
- const systemPrincipalId = deps.idGen.newId();
193
- await deps.repos.principals.save({
194
- id: systemPrincipalId,
195
- workspaceId,
196
- kind: "system",
197
- displayName: "System",
198
- status: "active",
199
- createdAt: nowIso,
200
- });
337
+ // Reuse the system principal a prior interrupted seed may already have written: `principals` has
338
+ // no unique index on kind, so a blind re-insert would leave TWO non-legacy system principals and
339
+ // the early-return branch above picking between them by list order.
340
+ const existingSystem = (await deps.repos.principals.list({ workspaceId })).find((row) => row.kind === "system" && row.id !== LEGACY_USER_LOCAL_PRINCIPAL_ID);
341
+ const systemPrincipalId = existingSystem?.id ?? deps.idGen.newId();
342
+ if (!existingSystem) {
343
+ await deps.repos.principals.save({
344
+ id: systemPrincipalId,
345
+ workspaceId,
346
+ kind: "system",
347
+ displayName: "System",
348
+ status: "active",
349
+ createdAt: nowIso,
350
+ });
351
+ }
201
352
  // REQ-09/EC-09: disabled legacy actor so historical `actorId='user-local'`
202
353
  // change-sets resolve without rewriting history.
203
354
  await deps.repos.principals.save({
@@ -212,23 +363,10 @@ export async function seedIdentity(required) {
212
363
  const { roleId: ownerRoleId } = await seedBuiltinRoleWithPolicy({
213
364
  deps,
214
365
  workspaceId,
215
- name: "owner",
216
- permissions: [],
366
+ name: OWNER_ROLE_NAME,
367
+ permissions: OWNER_ROLE_PERMISSIONS,
217
368
  nowIso,
218
369
  });
219
- // REQ-04/REQ-09: the owner policy holds the wildcard `*`, not an enumerated
220
- // list, so it automatically covers permissions features register later.
221
- const ownerPolicy = (await deps.repos.policies.list({ workspaceId })).find((row) => row.name === "owner-builtin-policy");
222
- if (!ownerPolicy)
223
- throw new Error("seedIdentity: owner policy was not created");
224
- await deps.repos.policyPermissions.save({
225
- id: deps.idGen.newId(),
226
- workspaceId,
227
- policyId: ownerPolicy.id,
228
- permission: "*",
229
- resourceType: null,
230
- constraintJson: null,
231
- });
232
370
  await seedBuiltinRoleWithPolicy({
233
371
  deps,
234
372
  workspaceId,
@@ -250,6 +388,12 @@ export async function seedIdentity(required) {
250
388
  permissions: BUILTIN_VIEWER_PERMISSIONS,
251
389
  nowIso,
252
390
  });
391
+ // Hashed BEFORE the owner principal row is written, not inline in the `users.save` below.
392
+ // argon2id is deliberately slow, which made it by far the widest window in this un-awaited,
393
+ // non-transactional sequence for a process to exit between the principal insert and the user
394
+ // insert that gives it meaning — leaving an orphan `kind: "user"` principal behind on every
395
+ // interrupted boot. Hashing first shrinks that window to a single adjacent await.
396
+ const ownerPasswordHash = await deps.hasher.hash(ownerPassword);
253
397
  const ownerPrincipalId = deps.idGen.newId();
254
398
  await deps.repos.principals.save({
255
399
  id: ownerPrincipalId,
@@ -264,14 +408,22 @@ export async function seedIdentity(required) {
264
408
  workspaceId,
265
409
  username: ownerUsername,
266
410
  email: input.ownerEmail,
267
- passwordHash: await deps.hasher.hash(ownerPassword),
411
+ passwordHash: ownerPasswordHash,
268
412
  });
269
- await deps.repos.principalRoles.save({
270
- id: deps.idGen.newId(),
413
+ // `principal_roles` carries no unique index either — same converge-don't-duplicate rule as the
414
+ // `role_policies` link in `seedBuiltinRoleWithPolicy`.
415
+ const ownerRoleLinks = await deps.repos.principalRoles.listByPrincipalId({
271
416
  workspaceId,
272
417
  principalId: ownerPrincipalId,
273
- roleId: ownerRoleId,
274
418
  });
419
+ if (!ownerRoleLinks.some((link) => link.roleId === ownerRoleId)) {
420
+ await deps.repos.principalRoles.save({
421
+ id: deps.idGen.newId(),
422
+ workspaceId,
423
+ principalId: ownerPrincipalId,
424
+ roleId: ownerRoleId,
425
+ });
426
+ }
275
427
  return { ownerPrincipalId, systemPrincipalId };
276
428
  }
277
429
  //# sourceMappingURL=seed.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"seed.js","sourceRoot":"","sources":["../../src/identity/seed.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"seed.js","sourceRoot":"","sources":["../../src/identity/seed.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,13 @@ export declare class LocalFsBlobStore implements BlobStorePort {
28
28
  get(input: {
29
29
  storageKey: string;
30
30
  }): Promise<Uint8Array>;
31
+ /**
32
+ * `ENOENT` (the path genuinely does not exist) resolves to `false`. Any other `stat()` failure
33
+ * (`EACCES` permission denied, `ENOTDIR`, `EIO`, ...) is rethrown raw — same "catch the one
34
+ * known code, rethrow everything else" shape {@link putIfAbsent}'s `EEXIST` handling above
35
+ * already uses — instead of collapsing into `false`: a caller branching on `exists()` must not
36
+ * mistake "this stat failed" for "the object was deleted".
37
+ */
31
38
  exists(input: {
32
39
  storageKey: string;
33
40
  }): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"blob-store.fs.d.ts","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAiB,YAAW,aAAa;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,oBAAoB;IAItC,OAAO,CAAC,WAAW;IAIb,GAAG,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAQ/D;;;;;;;;;;OAUG;IACG,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAenF,GAAG,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IASvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3D"}
1
+ {"version":3,"file":"blob-store.fs.d.ts","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAiB,YAAW,aAAa;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,oBAAoB;IAItC,OAAO,CAAC,WAAW;IAIb,GAAG,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAQ/D;;;;;;;;;;OAUG;IACG,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAenF,GAAG,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAI7D;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3D"}
@@ -58,13 +58,23 @@ export class LocalFsBlobStore {
58
58
  async get(input) {
59
59
  return readFile(this.resolvePath(input.storageKey));
60
60
  }
61
+ /**
62
+ * `ENOENT` (the path genuinely does not exist) resolves to `false`. Any other `stat()` failure
63
+ * (`EACCES` permission denied, `ENOTDIR`, `EIO`, ...) is rethrown raw — same "catch the one
64
+ * known code, rethrow everything else" shape {@link putIfAbsent}'s `EEXIST` handling above
65
+ * already uses — instead of collapsing into `false`: a caller branching on `exists()` must not
66
+ * mistake "this stat failed" for "the object was deleted".
67
+ */
61
68
  async exists(input) {
62
69
  try {
63
70
  await stat(this.resolvePath(input.storageKey));
64
71
  return true;
65
72
  }
66
- catch {
67
- return false;
73
+ catch (err) {
74
+ if (err.code === "ENOENT") {
75
+ return false;
76
+ }
77
+ throw err;
68
78
  }
69
79
  }
70
80
  async remove(input) {
@@ -1 +1 @@
1
- {"version":3,"file":"blob-store.fs.js","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD,MAAM,OAAO,gBAAgB;IACV,OAAO,CAAS;IAEjC,YAAY,IAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAEO,WAAW,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAmB;QAC3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,WAAW,CAAC,KAAmB;QACnC,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACxC,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAA6B;QACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;CACF"}
1
+ {"version":3,"file":"blob-store.fs.js","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD,MAAM,OAAO,gBAAgB;IACV,OAAO,CAAS;IAEjC,YAAY,IAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAEO,WAAW,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAmB;QAC3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,WAAW,CAAC,KAAmB;QACnC,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACxC,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAA6B;QACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACtD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;CACF"}
@@ -31,7 +31,7 @@
31
31
  */
32
32
  /** Recognized outputs. Anything not covered here falls back to the network's
33
33
  * default-safe unknown-binary label — see {@link sniffContentType}'s doc. */
34
- export type SniffedContentType = "image/png" | "image/jpeg" | "image/gif" | "image/webp" | "video/mp4" | "video/webm" | "text/html" | "image/svg+xml" | "application/octet-stream";
34
+ export type SniffedContentType = "image/png" | "image/jpeg" | "image/gif" | "image/webp" | "image/avif" | "video/mp4" | "video/webm" | "text/html" | "image/svg+xml" | "application/octet-stream";
35
35
  /**
36
36
  * Identifies a media type from `bytes`' leading magic bytes. Allowlist-shaped: only the formats
37
37
  * named in {@link SniffedContentType} are ever returned as something other than
@@ -1 +1 @@
1
- {"version":3,"file":"content-type-sniffer.d.ts","sourceRoot":"","sources":["../../src/media/content-type-sniffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;6EAC6E;AAC7E,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,WAAW,GACX,eAAe,GACf,0BAA0B,CAAC;AA2F/B;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,kBAAkB,CAatE"}
1
+ {"version":3,"file":"content-type-sniffer.d.ts","sourceRoot":"","sources":["../../src/media/content-type-sniffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;6EAC6E;AAC7E,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,WAAW,GACX,eAAe,GACf,0BAA0B,CAAC;AAwI/B;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,kBAAkB,CAgBtE"}
@@ -64,11 +64,55 @@ function isGif(bytes) {
64
64
  function isWebp(bytes) {
65
65
  return asciiEqualAt(bytes, 0, "RIFF") && asciiEqualAt(bytes, 8, "WEBP");
66
66
  }
67
- /** ISO-BMFF (MP4 and its siblings): a leading box whose 4-byte type tag at offset 4 is `ftyp`. The
68
- * box's own size field (offset 0-3) is deliberately not checked — it varies by file. */
69
- function isIsoBmffMp4(bytes) {
67
+ /** ISO-BMFF: a leading box whose 4-byte type tag at offset 4 is `ftyp`. The box's own size field
68
+ * (offset 0-3) is deliberately not checked here — it varies by file. This says only "some member
69
+ * of the ISO-BMFF family", NOT "MP4": AVIF, HEIC and MP4 all match it, which is why
70
+ * {@link isAvif} must run first and why {@link sniffContentType} treats this as the family's
71
+ * last-resort fallback rather than a positive MP4 identification. */
72
+ function isIsoBmffFtyp(bytes) {
70
73
  return asciiEqualAt(bytes, 4, "ftyp");
71
74
  }
75
+ /** ISO-BMFF brands that identify AVIF: a still image (`avif`) or an image sequence (`avis`). */
76
+ const AVIF_BRANDS = ["avif", "avis"];
77
+ const FTYP_MAJOR_BRAND_OFFSET = 8;
78
+ /** Compatible brands follow the major brand (offset 8) and 4-byte minor version (offset 12). */
79
+ const FTYP_COMPATIBLE_BRANDS_OFFSET = 16;
80
+ /** Bound on the compatible-brand list scan — real `ftyp` boxes carry a handful, never dozens. */
81
+ const MAX_SCANNED_COMPATIBLE_BRANDS = 16;
82
+ /** The `ftyp` box's declared end offset (big-endian size at bytes 0-3), clamped to the bytes
83
+ * actually present so a truncated or size-inflating file can never push the brand scan past the
84
+ * buffer or into unrelated trailing boxes. */
85
+ function ftypBoxEnd(bytes) {
86
+ if (bytes.length < FTYP_MAJOR_BRAND_OFFSET)
87
+ return 0;
88
+ const declared = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0;
89
+ return Math.min(declared, bytes.length);
90
+ }
91
+ function hasAvifBrandAt(bytes, offset) {
92
+ return AVIF_BRANDS.some((brand) => asciiEqualAt(bytes, offset, brand));
93
+ }
94
+ /**
95
+ * AVIF, distinguished from its ISO-BMFF siblings by brand rather than by the shared `ftyp` tag.
96
+ * The major brand alone is not sufficient: a great many real AVIF files declare the generic
97
+ * `mif1` (HEIF image) major brand and name `avif` only in the compatible-brand list, so both are
98
+ * checked. HEIC declares neither and is therefore never matched here — deliberate, since the
99
+ * installed libvips decodes AVIF but not HEIC.
100
+ */
101
+ function isAvif(bytes) {
102
+ if (!isIsoBmffFtyp(bytes))
103
+ return false;
104
+ if (hasAvifBrandAt(bytes, FTYP_MAJOR_BRAND_OFFSET))
105
+ return true;
106
+ const boxEnd = ftypBoxEnd(bytes);
107
+ for (let index = 0; index < MAX_SCANNED_COMPATIBLE_BRANDS; index++) {
108
+ const offset = FTYP_COMPATIBLE_BRANDS_OFFSET + index * 4;
109
+ if (offset + 4 > boxEnd)
110
+ return false;
111
+ if (hasAvifBrandAt(bytes, offset))
112
+ return true;
113
+ }
114
+ return false;
115
+ }
72
116
  function isWebm(bytes) {
73
117
  return bytesEqualAt(bytes, 0, EBML_SIGNATURE);
74
118
  }
@@ -127,7 +171,11 @@ export function sniffContentType(bytes) {
127
171
  return "image/gif";
128
172
  if (isWebp(bytes))
129
173
  return "image/webp";
130
- if (isIsoBmffMp4(bytes))
174
+ // MUST precede the MP4 check: AVIF is ISO-BMFF too, so the brand-blind `ftyp` test below would
175
+ // otherwise claim every AVIF as video/mp4 (the 2026-09-06 regression).
176
+ if (isAvif(bytes))
177
+ return "image/avif";
178
+ if (isIsoBmffFtyp(bytes))
131
179
  return "video/mp4";
132
180
  if (isWebm(bytes))
133
181
  return "video/webm";
@@ -1 +1 @@
1
- {"version":3,"file":"content-type-sniffer.js","sourceRoot":"","sources":["../../src/media/content-type-sniffer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"content-type-sniffer.js","sourceRoot":"","sources":["../../src/media/content-type-sniffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @file Server-side allowlist for `MediaRecord.htmlAttributes` (2026-09-07) — the enforcement half
3
+ * of a validator that ALSO has a browser-side copy in Tovu's admin
4
+ * (`apps/admin/src/features/media/rules.ts`, `parseMediaHtmlAttributes` and friends).
5
+ *
6
+ * Deliberately duplicated, not shared via one imported module, for the same reason this codebase
7
+ * already hand-copies `DEFAULT_ALLOWED_MIME_TYPES` into Tovu's `FILE_HANDLER_ALLOWED_MIME_TYPES`/
8
+ * `IMPORTABLE_CONTENT_TYPES`: `@jini-ai/cms/media`'s barrel (`index.ts`) re-exports files that
9
+ * import real Node built-ins (`node:crypto` in `media-service.ts`, `node:fs` in
10
+ * `blob-store.fs.ts`, native `sharp` bindings in `image-transformer.sharp.ts`) — importing this
11
+ * subpath from a browser-bundled Vite app (Tovu's `apps/admin`) risks pulling those into the admin
12
+ * SPA's bundle even if only this one pure function is actually used, and this admin's own copy
13
+ * already exists, tested, with no such risk. This file is the copy every Node-side consumer
14
+ * (`media-service.ts`'s own `updateMediaMetadata`, and Tovu's `apps/website` render path, both pure
15
+ * backend code) can safely import from `@jini-ai/cms/media` instead of re-deriving the rules a
16
+ * third time.
17
+ *
18
+ * THE RULES THEMSELVES ARE NOT REDESIGNED HERE — this is a verbatim port of the admin copy's logic
19
+ * (allowlist membership, `on*`/`javascript:` precedence, the tokenizer, the four rejection reasons).
20
+ * Extend `MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES` in BOTH copies together if a new attribute is ever
21
+ * needed — that is the one piece of drift risk this duplication accepts, the same risk every other
22
+ * hand-copied list in this codebase already accepts.
23
+ *
24
+ * This is a SECURITY boundary, not a syntax convenience: media metadata is authored in Tovu's admin
25
+ * but rendered on the public site, so a free-text HTML-attribute passthrough is a stored-XSS vector
26
+ * (`onerror`, `onclick`, `style`, `href="javascript:"`, any `on*` handler) the moment it reaches a
27
+ * public page. A client-side-only check is not a control, since the API accepts whatever a caller
28
+ * sends — this file is what makes the write path (`updateMediaMetadata`) and the render path (a
29
+ * host's own tag-building code) actually enforce it, not just the admin form.
30
+ */
31
+ /**
32
+ * Exact-match attribute names the allowlist accepts beyond the open-ended `data-`/`aria-` prefix
33
+ * families (checked separately in {@link isAllowedMediaHtmlAttributeName}). Picked for the owner's
34
+ * stated near-term uses (animations, custom WebMCP hooks) plus the standard `<img>`/`<video>`
35
+ * attributes those uses actually need; extend this list, not the parser, when a new one is needed —
36
+ * and keep it in sync with the identical constant in Tovu's admin copy (see this file's header).
37
+ */
38
+ export declare const MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES: readonly ["loading", "decoding", "playsinline", "muted", "loop", "autoplay", "poster"];
39
+ /** Whether `name` is on the allowlist — a well-formed attribute name
40
+ * ({@link MEDIA_HTML_ATTRIBUTE_NAME_PATTERN}) that is either an exact match against
41
+ * {@link MEDIA_HTML_ATTRIBUTE_ALLOWED_NAMES} or carries a `data-`/`aria-` prefix (both open-ended
42
+ * families with no fixed suffix list). Case-insensitive: HTML attribute names are themselves
43
+ * case-insensitive, and an operator typing `DATA-FOO` should not slip past a lowercase-only check.
44
+ *
45
+ * @complexity O(n) in the name's length (one anchored regex test), then O(1) — one prefix check,
46
+ * one fixed-length array lookup.
47
+ */
48
+ export declare function isAllowedMediaHtmlAttributeName(name: string): boolean;
49
+ /** Why one parsed attribute token was rejected — see {@link parseMediaHtmlAttributes}'s own doc for
50
+ * why `event-handler`/`javascript-url` are checked, and reported, ahead of plain allowlist
51
+ * membership. */
52
+ export type MediaHtmlAttributeRejectionReason = "disallowed-name" | "event-handler" | "javascript-url" | "malformed";
53
+ export interface MediaHtmlAttributeError {
54
+ reason: MediaHtmlAttributeRejectionReason;
55
+ /** The exact attribute name (or, for `malformed`, the unparsable fragment) — never a generic
56
+ * "invalid input" (owner requirement: a visible, specific error naming the rejected attribute). */
57
+ attribute: string;
58
+ }
59
+ export interface ParsedMediaHtmlAttributes {
60
+ /** Lowercased attribute name -> value. A boolean attribute (`muted`, written with no
61
+ * `="..."`) maps to `""` — recording only that it was present; how a valueless attribute gets
62
+ * emitted onto the real tag is the renderer's decision, not this parser's. */
63
+ attributes: Record<string, string>;
64
+ /** `null` when every token in the input is allowed and safe; otherwise the FIRST rejection found
65
+ * scanning left to right — one specific, visible reason at a time, not a batch of every problem
66
+ * in the string. */
67
+ error: MediaHtmlAttributeError | null;
68
+ }
69
+ /**
70
+ * Parses the `htmlAttributes` field's free text (`name="value" name2="value2"`, or a bare boolean
71
+ * `name`) into a validated attribute map, rejecting anything not on the allowlist. Nothing here
72
+ * tries to sanitize or escape an otherwise-disallowed name into something safe — it is rejected
73
+ * outright, and the caller must show the reason (not silently drop it) so an operator can tell a
74
+ * typo from a hard "no".
75
+ *
76
+ * @complexity Time O(n) in `text`'s length (one regex pass over it), space O(k) for k parsed
77
+ * attributes.
78
+ */
79
+ export declare function parseMediaHtmlAttributes(text: string): ParsedMediaHtmlAttributes;
80
+ /** Formats a {@link MediaHtmlAttributeError} into a plain-English message naming the rejected
81
+ * attribute (owner requirement) — the server-side, non-localized counterpart to the admin's own
82
+ * `describeMediaHtmlAttributeError` (which additionally runs the message through `MEDIA_DICT` for
83
+ * the operator's locale). Domain errors elsewhere in this file (`MediaValidationError`'s other
84
+ * messages) are likewise always plain English, so this matches that existing convention rather
85
+ * than inventing a localized-error contract this service has never had.
86
+ *
87
+ * @complexity O(1).
88
+ */
89
+ export declare function describeMediaHtmlAttributeError(error: MediaHtmlAttributeError): string;
90
+ //# sourceMappingURL=html-attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-attributes.d.ts","sourceRoot":"","sources":["../../src/media/html-attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,wFAQrC,CAAC;AAsBX;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKrE;AAED;;kBAEkB;AAClB,MAAM,MAAM,iCAAiC,GAAG,iBAAiB,GAAG,eAAe,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAErH,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,iCAAiC,CAAC;IAC1C;wGACoG;IACpG,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC;;mFAE+E;IAC/E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;yBAEqB;IACrB,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACvC;AAuBD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,CA0BhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAKtF"}