@de-otio/trellis 0.10.11 → 0.12.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 (199) hide show
  1. package/dist/env.d.ts +232 -0
  2. package/dist/env.d.ts.map +1 -1
  3. package/dist/env.js +221 -0
  4. package/dist/env.js.map +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/lambda/media-completion-worker.d.ts +175 -0
  10. package/dist/lambda/media-completion-worker.d.ts.map +1 -0
  11. package/dist/lambda/media-completion-worker.js +373 -0
  12. package/dist/lambda/media-completion-worker.js.map +1 -0
  13. package/dist/lambda/media-processing-worker.d.ts +172 -1
  14. package/dist/lambda/media-processing-worker.d.ts.map +1 -1
  15. package/dist/lambda/media-processing-worker.js +343 -49
  16. package/dist/lambda/media-processing-worker.js.map +1 -1
  17. package/dist/lib/app.d.ts.map +1 -1
  18. package/dist/lib/app.js +5 -0
  19. package/dist/lib/app.js.map +1 -1
  20. package/dist/lib/encrypted-settings/config.d.ts +13 -0
  21. package/dist/lib/encrypted-settings/config.d.ts.map +1 -0
  22. package/dist/lib/encrypted-settings/config.js +19 -0
  23. package/dist/lib/encrypted-settings/config.js.map +1 -0
  24. package/dist/lib/encrypted-settings/encrypted-settings-handler.d.ts +57 -0
  25. package/dist/lib/encrypted-settings/encrypted-settings-handler.d.ts.map +1 -0
  26. package/dist/lib/encrypted-settings/encrypted-settings-handler.js +178 -0
  27. package/dist/lib/encrypted-settings/encrypted-settings-handler.js.map +1 -0
  28. package/dist/lib/encrypted-settings/encrypted-settings-store.d.ts +110 -0
  29. package/dist/lib/encrypted-settings/encrypted-settings-store.d.ts.map +1 -0
  30. package/dist/lib/encrypted-settings/encrypted-settings-store.js +103 -0
  31. package/dist/lib/encrypted-settings/encrypted-settings-store.js.map +1 -0
  32. package/dist/lib/encrypted-settings/types.d.ts +26 -0
  33. package/dist/lib/encrypted-settings/types.d.ts.map +1 -0
  34. package/dist/lib/encrypted-settings/types.js +27 -0
  35. package/dist/lib/encrypted-settings/types.js.map +1 -0
  36. package/dist/lib/exif-stripper.d.ts +37 -22
  37. package/dist/lib/exif-stripper.d.ts.map +1 -1
  38. package/dist/lib/exif-stripper.js +101 -41
  39. package/dist/lib/exif-stripper.js.map +1 -1
  40. package/dist/lib/media/cas-keys.d.ts +63 -0
  41. package/dist/lib/media/cas-keys.d.ts.map +1 -0
  42. package/dist/lib/media/cas-keys.js +102 -0
  43. package/dist/lib/media/cas-keys.js.map +1 -0
  44. package/dist/lib/media/classify-worker-error.d.ts +48 -0
  45. package/dist/lib/media/classify-worker-error.d.ts.map +1 -0
  46. package/dist/lib/media/classify-worker-error.js +319 -0
  47. package/dist/lib/media/classify-worker-error.js.map +1 -0
  48. package/dist/lib/media/dedupe-key.d.ts +29 -0
  49. package/dist/lib/media/dedupe-key.d.ts.map +1 -0
  50. package/dist/lib/media/dedupe-key.js +49 -0
  51. package/dist/lib/media/dedupe-key.js.map +1 -0
  52. package/dist/lib/media/duration-cap.d.ts +30 -0
  53. package/dist/lib/media/duration-cap.d.ts.map +1 -0
  54. package/dist/lib/media/duration-cap.js +37 -0
  55. package/dist/lib/media/duration-cap.js.map +1 -0
  56. package/dist/lib/media/ffmpeg-args.d.ts +83 -0
  57. package/dist/lib/media/ffmpeg-args.d.ts.map +1 -0
  58. package/dist/lib/media/ffmpeg-args.js +119 -0
  59. package/dist/lib/media/ffmpeg-args.js.map +1 -0
  60. package/dist/lib/media/media-ports.d.ts +126 -0
  61. package/dist/lib/media/media-ports.d.ts.map +1 -0
  62. package/dist/lib/media/media-ports.js +129 -0
  63. package/dist/lib/media/media-ports.js.map +1 -0
  64. package/dist/lib/media/media-upsert.d.ts +55 -0
  65. package/dist/lib/media/media-upsert.d.ts.map +1 -0
  66. package/dist/lib/media/media-upsert.js +38 -0
  67. package/dist/lib/media/media-upsert.js.map +1 -0
  68. package/dist/lib/media/moderation-provider.d.ts +111 -0
  69. package/dist/lib/media/moderation-provider.d.ts.map +1 -0
  70. package/dist/lib/media/moderation-provider.js +130 -0
  71. package/dist/lib/media/moderation-provider.js.map +1 -0
  72. package/dist/lib/media/moderation-resolved-payload.d.ts +48 -0
  73. package/dist/lib/media/moderation-resolved-payload.d.ts.map +1 -0
  74. package/dist/lib/media/moderation-resolved-payload.js +37 -0
  75. package/dist/lib/media/moderation-resolved-payload.js.map +1 -0
  76. package/dist/lib/media/moderation-status.d.ts +98 -0
  77. package/dist/lib/media/moderation-status.d.ts.map +1 -0
  78. package/dist/lib/media/moderation-status.js +122 -0
  79. package/dist/lib/media/moderation-status.js.map +1 -0
  80. package/dist/lib/media/processing-types.d.ts +45 -0
  81. package/dist/lib/media/processing-types.d.ts.map +1 -0
  82. package/dist/lib/media/processing-types.js +9 -0
  83. package/dist/lib/media/processing-types.js.map +1 -0
  84. package/dist/lib/media/promote-decision.d.ts +64 -0
  85. package/dist/lib/media/promote-decision.d.ts.map +1 -0
  86. package/dist/lib/media/promote-decision.js +76 -0
  87. package/dist/lib/media/promote-decision.js.map +1 -0
  88. package/dist/lib/media/quota-check.d.ts +22 -0
  89. package/dist/lib/media/quota-check.d.ts.map +1 -0
  90. package/dist/lib/media/quota-check.js +42 -0
  91. package/dist/lib/media/quota-check.js.map +1 -0
  92. package/dist/lib/media/quota-types.d.ts +15 -0
  93. package/dist/lib/media/quota-types.d.ts.map +1 -0
  94. package/dist/lib/media/quota-types.js +9 -0
  95. package/dist/lib/media/quota-types.js.map +1 -0
  96. package/dist/lib/media/route-upload.d.ts +58 -0
  97. package/dist/lib/media/route-upload.d.ts.map +1 -0
  98. package/dist/lib/media/route-upload.js +80 -0
  99. package/dist/lib/media/route-upload.js.map +1 -0
  100. package/dist/lib/media/serve-gate.d.ts +51 -0
  101. package/dist/lib/media/serve-gate.d.ts.map +1 -0
  102. package/dist/lib/media/serve-gate.js +68 -0
  103. package/dist/lib/media/serve-gate.js.map +1 -0
  104. package/dist/lib/media/tenant-resolution.d.ts +42 -0
  105. package/dist/lib/media/tenant-resolution.d.ts.map +1 -0
  106. package/dist/lib/media/tenant-resolution.js +45 -0
  107. package/dist/lib/media/tenant-resolution.js.map +1 -0
  108. package/dist/lib/media/text-moderation.d.ts +28 -0
  109. package/dist/lib/media/text-moderation.d.ts.map +1 -0
  110. package/dist/lib/media/text-moderation.js +62 -0
  111. package/dist/lib/media/text-moderation.js.map +1 -0
  112. package/dist/lib/media/track-verdict.d.ts +45 -0
  113. package/dist/lib/media/track-verdict.d.ts.map +1 -0
  114. package/dist/lib/media/track-verdict.js +52 -0
  115. package/dist/lib/media/track-verdict.js.map +1 -0
  116. package/dist/lib/media/transcript-moderation.d.ts +47 -0
  117. package/dist/lib/media/transcript-moderation.d.ts.map +1 -0
  118. package/dist/lib/media/transcript-moderation.js +70 -0
  119. package/dist/lib/media/transcript-moderation.js.map +1 -0
  120. package/dist/lib/media-handler.d.ts.map +1 -1
  121. package/dist/lib/media-handler.js +15 -9
  122. package/dist/lib/media-handler.js.map +1 -1
  123. package/dist/lib/notification-handler.d.ts +11 -4
  124. package/dist/lib/notification-handler.d.ts.map +1 -1
  125. package/dist/lib/notification-handler.js +161 -29
  126. package/dist/lib/notification-handler.js.map +1 -1
  127. package/dist/lib/post-handler.d.ts.map +1 -1
  128. package/dist/lib/post-handler.js +4 -1
  129. package/dist/lib/post-handler.js.map +1 -1
  130. package/dist/lib/realtime/block-store.d.ts +61 -0
  131. package/dist/lib/realtime/block-store.d.ts.map +1 -0
  132. package/dist/lib/realtime/block-store.js +0 -0
  133. package/dist/lib/realtime/block-store.js.map +1 -0
  134. package/dist/lib/realtime/channel.d.ts +34 -0
  135. package/dist/lib/realtime/channel.d.ts.map +1 -0
  136. package/dist/lib/realtime/channel.js +100 -0
  137. package/dist/lib/realtime/channel.js.map +1 -0
  138. package/dist/lib/realtime/delivery-policy.d.ts +51 -0
  139. package/dist/lib/realtime/delivery-policy.d.ts.map +1 -0
  140. package/dist/lib/realtime/delivery-policy.js +98 -0
  141. package/dist/lib/realtime/delivery-policy.js.map +1 -0
  142. package/dist/lib/realtime/index.d.ts +21 -0
  143. package/dist/lib/realtime/index.d.ts.map +1 -0
  144. package/dist/lib/realtime/index.js +39 -0
  145. package/dist/lib/realtime/index.js.map +1 -0
  146. package/dist/lib/realtime/no-op-transport.d.ts +10 -0
  147. package/dist/lib/realtime/no-op-transport.d.ts.map +1 -0
  148. package/dist/lib/realtime/no-op-transport.js +44 -0
  149. package/dist/lib/realtime/no-op-transport.js.map +1 -0
  150. package/dist/lib/realtime/poll-transport.d.ts +11 -0
  151. package/dist/lib/realtime/poll-transport.d.ts.map +1 -0
  152. package/dist/lib/realtime/poll-transport.js +68 -0
  153. package/dist/lib/realtime/poll-transport.js.map +1 -0
  154. package/dist/lib/realtime/push-notifier.d.ts +39 -0
  155. package/dist/lib/realtime/push-notifier.d.ts.map +1 -0
  156. package/dist/lib/realtime/push-notifier.js +76 -0
  157. package/dist/lib/realtime/push-notifier.js.map +1 -0
  158. package/dist/lib/realtime/realtime-transport.d.ts +2 -0
  159. package/dist/lib/realtime/realtime-transport.d.ts.map +1 -0
  160. package/dist/lib/realtime/realtime-transport.js +23 -0
  161. package/dist/lib/realtime/realtime-transport.js.map +1 -0
  162. package/dist/lib/realtime/setting-store.d.ts +30 -0
  163. package/dist/lib/realtime/setting-store.d.ts.map +1 -0
  164. package/dist/lib/realtime/setting-store.js +0 -0
  165. package/dist/lib/realtime/setting-store.js.map +1 -0
  166. package/dist/lib/realtime/types.d.ts +200 -0
  167. package/dist/lib/realtime/types.d.ts.map +1 -0
  168. package/dist/lib/realtime/types.js +61 -0
  169. package/dist/lib/realtime/types.js.map +1 -0
  170. package/dist/lib/routes/index.d.ts.map +1 -1
  171. package/dist/lib/routes/index.js +3 -0
  172. package/dist/lib/routes/index.js.map +1 -1
  173. package/dist/lib/routes/media.d.ts +21 -0
  174. package/dist/lib/routes/media.d.ts.map +1 -1
  175. package/dist/lib/routes/media.js +584 -483
  176. package/dist/lib/routes/media.js.map +1 -1
  177. package/dist/lib/routes/settings.d.ts +17 -0
  178. package/dist/lib/routes/settings.d.ts.map +1 -0
  179. package/dist/lib/routes/settings.js +187 -0
  180. package/dist/lib/routes/settings.js.map +1 -0
  181. package/dist/lib/services/image-normalizer.d.ts +64 -6
  182. package/dist/lib/services/image-normalizer.d.ts.map +1 -1
  183. package/dist/lib/services/image-normalizer.js +88 -6
  184. package/dist/lib/services/image-normalizer.js.map +1 -1
  185. package/dist/lib/services/media-upload-service.d.ts +2 -2
  186. package/dist/lib/services/media-upload-service.d.ts.map +1 -1
  187. package/dist/lib/services/media-upload-service.js +22 -21
  188. package/dist/lib/services/media-upload-service.js.map +1 -1
  189. package/dist/lib/tenant-scope.d.ts.map +1 -1
  190. package/dist/lib/tenant-scope.js +18 -1
  191. package/dist/lib/tenant-scope.js.map +1 -1
  192. package/package.json +23 -22
  193. package/prisma/migrations/20260620051144_add_encrypted_user_settings/migration.sql +24 -0
  194. package/prisma/migrations/20260620120000_add_blocked_users/migration.sql +29 -0
  195. package/prisma/migrations/20260625000000_media_tenant_scope_and_moderation_status/migration.sql +49 -0
  196. package/prisma/migrations/20260625000001_p0b_moderation_jobs/migration.sql +73 -0
  197. package/prisma/schema.prisma +133 -15
  198. package/src/lambda/media-completion-worker.ts +567 -0
  199. package/src/lambda/media-processing-worker.ts +508 -59
@@ -0,0 +1,100 @@
1
+ // CONTRACT: stable — coordinate changes. See types.ts banner.
2
+ //
3
+ // Channel naming + the subscription authorization boundary. Per §2.1/§2.2 of
4
+ // the frozen contract, the canonical path is produced ONLY by `channelName()`
5
+ // and parsed ONLY by `parseChannel()`; `authorizeSubscription()` is THE
6
+ // security boundary — identity comes from a VerifiedIdentity (Cognito claims),
7
+ // never an ambient Session and never a client-asserted path.
8
+ /** Canonical path grammar: /{kind}/{tenantId}/{scopeType}/{scopeId}. */
9
+ const VALID_KINDS = new Set([
10
+ "wakeup",
11
+ "setting_sync",
12
+ "safety",
13
+ "message",
14
+ "thread",
15
+ ]);
16
+ const VALID_SCOPE_TYPES = new Set([
17
+ "user",
18
+ "conversation",
19
+ "thread",
20
+ ]);
21
+ /** A path segment may not be empty and may not contain a path separator. */
22
+ function isValidSegment(s) {
23
+ return s.length > 0 && !s.includes("/");
24
+ }
25
+ /**
26
+ * Produce the canonical channel path. This is the ONLY way a channel string is
27
+ * minted server-side; the Skybber `@skybber/realtime-channels` parser must
28
+ * round-trip this output.
29
+ */
30
+ export function channelName(c) {
31
+ if (!VALID_KINDS.has(c.kind)) {
32
+ throw new Error(`channelName: invalid kind "${String(c.kind)}"`);
33
+ }
34
+ if (!VALID_SCOPE_TYPES.has(c.scopeType)) {
35
+ throw new Error(`channelName: invalid scopeType "${String(c.scopeType)}"`);
36
+ }
37
+ if (!isValidSegment(c.tenantId) || !isValidSegment(c.scopeId)) {
38
+ throw new Error("channelName: tenantId/scopeId must be non-empty, no slash");
39
+ }
40
+ return `/${c.kind}/${c.tenantId}/${c.scopeType}/${c.scopeId}`;
41
+ }
42
+ /**
43
+ * Parse a canonical channel path. Returns `null` on ANY malformed input — a
44
+ * leading-slash-less path, wrong arity, unknown kind/scopeType, or an empty
45
+ * segment.
46
+ */
47
+ export function parseChannel(path) {
48
+ if (typeof path !== "string" || !path.startsWith("/"))
49
+ return null;
50
+ // Drop the leading "" produced by the leading slash; require exactly 4 parts.
51
+ const parts = path.split("/");
52
+ if (parts.length !== 5 || parts[0] !== "")
53
+ return null;
54
+ const [, kind, tenantId, scopeType, scopeId] = parts;
55
+ if (!VALID_KINDS.has(kind))
56
+ return null;
57
+ if (!VALID_SCOPE_TYPES.has(scopeType))
58
+ return null;
59
+ if (!isValidSegment(tenantId) || !isValidSegment(scopeId))
60
+ return null;
61
+ return {
62
+ kind: kind,
63
+ tenantId,
64
+ scopeType: scopeType,
65
+ scopeId,
66
+ };
67
+ }
68
+ /**
69
+ * Build a user-scoped channel (v1: the only scope). `kind` is constrained to
70
+ * the v1 user-scoped kinds; `message`/`thread` are deferred and excluded.
71
+ */
72
+ export function channelFor(kind, scope) {
73
+ return {
74
+ kind,
75
+ tenantId: scope.tenantId,
76
+ scopeType: "user",
77
+ scopeId: scope.userId,
78
+ };
79
+ }
80
+ /**
81
+ * THE security boundary. The channel is a client *assertion* this checks
82
+ * against a server-verified identity.
83
+ *
84
+ * ALLOW iff `c.tenantId === id.tenantId` AND
85
+ * scopeType "user" -> `c.scopeId === id.userId`
86
+ * scopeType conversation/thread -> membership(id.userId, c.scopeId) [v1: false]
87
+ *
88
+ * End-user PUBLISH is ALWAYS denied elsewhere (publish is server-only via IAM);
89
+ * this function governs SUBSCRIBE only.
90
+ */
91
+ export function authorizeSubscription(id, c) {
92
+ if (c.tenantId !== id.tenantId)
93
+ return false;
94
+ if (c.scopeType === "user") {
95
+ return c.scopeId === id.userId;
96
+ }
97
+ // conversation / thread membership — DEFERRED in v1, deny.
98
+ return false;
99
+ }
100
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../../src/lib/realtime/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { DeliveryContext, DeliveryDecision, DeliveryPolicyResolver } from "./types.js";
2
+ import type { NotificationType } from "@prisma/client";
3
+ /**
4
+ * Notification types that ALWAYS deliver — they bypass user preference and
5
+ * quiet hours. Migrated verbatim from `notification-handler.ts`'s
6
+ * `ALWAYS_DELIVER_TYPES`. This is the critical-always floor.
7
+ */
8
+ export declare const ALWAYS_DELIVER_TYPES: ReadonlySet<NotificationType>;
9
+ /**
10
+ * Track D runtime config for the floor. The minor-protection rule needs the set
11
+ * of "manipulative re-engagement" NotificationTypes to deny to non-adults. Per
12
+ * the threshold-secrecy invariant (CLAUDE.md rule 8) this list is RUNTIME CONFIG
13
+ * — passed in here, never a compiled-in constant sprinkled at a call site.
14
+ * v1 ships it EMPTY (no such type exists yet); a deployment populates it via env.
15
+ */
16
+ export interface DeliveryFloorConfig {
17
+ /** NotificationTypes that re-engage and are denied to non-adult recipients. */
18
+ reengagementTypes?: ReadonlySet<NotificationType>;
19
+ }
20
+ /**
21
+ * The WS1 + Track D default resolver. Pure and synchronous over `DeliveryContext`
22
+ * (the caller does any async lookups and passes resolved signals in):
23
+ *
24
+ * 1. ALWAYS_DELIVER_TYPES (SAFETY_ALERT, PARENTAL_LINK) bypass everything ->
25
+ * `{ deliver: true }`. Safety must NOT be over-blocked: this wins over the
26
+ * blocked-sender and minor-protection floor below.
27
+ * 2. Non-configurable FLOOR (checked only when the caller supplies the input):
28
+ * - blocked sender: the caller resolves block-set membership async (via
29
+ * BlockStore) and populates `ctx.senderUserId` ONLY when the sender is
30
+ * blocked — so presence of `senderUserId` == "in the recipient's block
31
+ * set". The decision is a hard drop no preference can override.
32
+ * - minor-protection: a non-adult recipient (`recipientAgeTier` CHILD/TEEN)
33
+ * targeted by a configured re-engagement type is dropped.
34
+ * 3. Else honor preference (caller pre-resolves `deliver:false`/`preference`)
35
+ * and quiet hours.
36
+ *
37
+ * Note on preference: in the existing handler the type-preference check happens
38
+ * BEFORE creating the row (preference-off => no row at all), which is a
39
+ * different outcome from quiet-hours (row created with deliveredAt=null). The
40
+ * caller maps the decision reasons accordingly. To keep the resolver pure and
41
+ * total it accepts the preference outcome via `ctx` indirectly: the caller only
42
+ * invokes the resolver's quiet-hours path once preference has passed. For a
43
+ * single source of truth the resolver still exposes the full decision so a
44
+ * push-only caller (WS4) can gate solely on it.
45
+ */
46
+ export declare class CalmDeliveryResolver implements DeliveryPolicyResolver {
47
+ private readonly reengagementTypes;
48
+ constructor(config?: DeliveryFloorConfig);
49
+ decide(ctx: DeliveryContext): DeliveryDecision;
50
+ }
51
+ //# sourceMappingURL=delivery-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-policy.d.ts","sourceRoot":"","sources":["../../../src/lib/realtime/delivery-policy.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,gBAAgB,CAE3B,CAAC;AA8BrC;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;CACnD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,oBAAqB,YAAW,sBAAsB;IACjE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAgC;gBAEtD,MAAM,GAAE,mBAAwB;IAK5C,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,gBAAgB;CAgC/C"}
@@ -0,0 +1,98 @@
1
+ // CONTRACT: stable — coordinate changes. See types.ts banner.
2
+ //
3
+ // The DeliveryPolicyResolver port and the CalmDeliveryResolver default. Per §3
4
+ // of the frozen contract, WS1 (not WS4) owns migrating the existing hardcoded
5
+ // notification floor into CalmDeliveryResolver, under a golden test that pins
6
+ // byte-identical behavior. The same resolver decision drives BOTH the
7
+ // persistence `deliveredAt` choice AND the (default-off) push hand-off.
8
+ /**
9
+ * Notification types that ALWAYS deliver — they bypass user preference and
10
+ * quiet hours. Migrated verbatim from `notification-handler.ts`'s
11
+ * `ALWAYS_DELIVER_TYPES`. This is the critical-always floor.
12
+ */
13
+ export const ALWAYS_DELIVER_TYPES = new Set(["SAFETY_ALERT", "PARENTAL_LINK"]);
14
+ /**
15
+ * Reproduce the existing `notification-handler.ts` quiet-hours check exactly.
16
+ *
17
+ * The core encodes `User.quietHoursStart/End` (minutes-since-midnight integers)
18
+ * as decimal strings in `QuietHoursConfig.start/end`, and derives the current
19
+ * minute from `ctx.now` (rather than an ambient `new Date()`), so the decision
20
+ * is deterministic. The wrap-around / same-day arithmetic mirrors
21
+ * `NotificationHandler.isInQuietHours`.
22
+ */
23
+ function isInQuietHours(quietHours, now) {
24
+ if (!quietHours || !quietHours.enabled)
25
+ return false;
26
+ const start = Number.parseInt(quietHours.start, 10);
27
+ const end = Number.parseInt(quietHours.end, 10);
28
+ if (!Number.isFinite(start) || !Number.isFinite(end))
29
+ return false;
30
+ const minutesSinceMidnight = now.getHours() * 60 + now.getMinutes();
31
+ // Overnight window (e.g. 22:00 -> 07:00).
32
+ if (start > end) {
33
+ return minutesSinceMidnight >= start || minutesSinceMidnight < end;
34
+ }
35
+ // Same-day window (e.g. 13:00 -> 15:00).
36
+ return minutesSinceMidnight >= start && minutesSinceMidnight < end;
37
+ }
38
+ /**
39
+ * The WS1 + Track D default resolver. Pure and synchronous over `DeliveryContext`
40
+ * (the caller does any async lookups and passes resolved signals in):
41
+ *
42
+ * 1. ALWAYS_DELIVER_TYPES (SAFETY_ALERT, PARENTAL_LINK) bypass everything ->
43
+ * `{ deliver: true }`. Safety must NOT be over-blocked: this wins over the
44
+ * blocked-sender and minor-protection floor below.
45
+ * 2. Non-configurable FLOOR (checked only when the caller supplies the input):
46
+ * - blocked sender: the caller resolves block-set membership async (via
47
+ * BlockStore) and populates `ctx.senderUserId` ONLY when the sender is
48
+ * blocked — so presence of `senderUserId` == "in the recipient's block
49
+ * set". The decision is a hard drop no preference can override.
50
+ * - minor-protection: a non-adult recipient (`recipientAgeTier` CHILD/TEEN)
51
+ * targeted by a configured re-engagement type is dropped.
52
+ * 3. Else honor preference (caller pre-resolves `deliver:false`/`preference`)
53
+ * and quiet hours.
54
+ *
55
+ * Note on preference: in the existing handler the type-preference check happens
56
+ * BEFORE creating the row (preference-off => no row at all), which is a
57
+ * different outcome from quiet-hours (row created with deliveredAt=null). The
58
+ * caller maps the decision reasons accordingly. To keep the resolver pure and
59
+ * total it accepts the preference outcome via `ctx` indirectly: the caller only
60
+ * invokes the resolver's quiet-hours path once preference has passed. For a
61
+ * single source of truth the resolver still exposes the full decision so a
62
+ * push-only caller (WS4) can gate solely on it.
63
+ */
64
+ export class CalmDeliveryResolver {
65
+ reengagementTypes;
66
+ constructor(config = {}) {
67
+ this.reengagementTypes =
68
+ config.reengagementTypes ?? new Set();
69
+ }
70
+ decide(ctx) {
71
+ // 1. Critical-always bypass — wins over the floor so safety is never
72
+ // over-blocked (a blocked sender or a minor still gets SAFETY_ALERT /
73
+ // PARENTAL_LINK).
74
+ if (ALWAYS_DELIVER_TYPES.has(ctx.type)) {
75
+ return { deliver: true };
76
+ }
77
+ // 2. Non-configurable floor.
78
+ // 2a. Blocked sender. The caller has already resolved block-set
79
+ // membership and only sets `senderUserId` when the sender IS blocked,
80
+ // so its presence is the deny signal. Hard drop, no override.
81
+ if (ctx.senderUserId !== undefined) {
82
+ return { deliver: false, reason: "blocked_sender" };
83
+ }
84
+ // 2b. Minor protection. A non-adult recipient targeted by a configured
85
+ // manipulative re-engagement type is dropped (FLOOR, not preference).
86
+ if (ctx.recipientAgeTier !== undefined &&
87
+ ctx.recipientAgeTier !== "ADULT" &&
88
+ this.reengagementTypes.has(ctx.type)) {
89
+ return { deliver: false, reason: "floor" };
90
+ }
91
+ // 3. Quiet hours (preference is handled by the caller; see class doc).
92
+ if (isInQuietHours(ctx.quietHours, ctx.now)) {
93
+ return { deliver: false, reason: "quiet_hours" };
94
+ }
95
+ return { deliver: true };
96
+ }
97
+ }
98
+ //# sourceMappingURL=delivery-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-policy.js","sourceRoot":"","sources":["../../../src/lib/realtime/delivery-policy.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,8EAA8E;AAC9E,sEAAsE;AACtE,wEAAwE;AASxE;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAkC,IAAI,GAAG,CAExE,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;AAErC;;;;;;;;GAQG;AACH,SAAS,cAAc,CACrB,UAAyC,EACzC,GAAS;IAET,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAEnE,MAAM,oBAAoB,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;IAEpE,0CAA0C;IAC1C,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;QAChB,OAAO,oBAAoB,IAAI,KAAK,IAAI,oBAAoB,GAAG,GAAG,CAAC;IACrE,CAAC;IACD,yCAAyC;IACzC,OAAO,oBAAoB,IAAI,KAAK,IAAI,oBAAoB,GAAG,GAAG,CAAC;AACrE,CAAC;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,OAAO,oBAAoB;IACd,iBAAiB,CAAgC;IAElE,YAAY,SAA8B,EAAE;QAC1C,IAAI,CAAC,iBAAiB;YACpB,MAAM,CAAC,iBAAiB,IAAI,IAAI,GAAG,EAAoB,CAAC;IAC5D,CAAC;IAED,MAAM,CAAC,GAAoB;QACzB,qEAAqE;QACrE,yEAAyE;QACzE,qBAAqB;QACrB,IAAI,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,6BAA6B;QAC7B,mEAAmE;QACnE,6EAA6E;QAC7E,qEAAqE;QACrE,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACtD,CAAC;QACD,0EAA0E;QAC1E,6EAA6E;QAC7E,IACE,GAAG,CAAC,gBAAgB,KAAK,SAAS;YAClC,GAAG,CAAC,gBAAgB,KAAK,OAAO;YAChC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EACpC,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC7C,CAAC;QAED,uEAAuE;QACvE,IAAI,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QACnD,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ export type { Channel, ChannelKind, ScopeType, VerifiedIdentity, DeliveryTarget, DeliveryResult, DeliveryContext, DeliveryDecision, QuietHoursConfig, WakeupEnvelope, EncryptedBlob, PutResult, SettingStore, ChangedSettingMeta, ChangeCursorStore, RealtimeTransport, DeliveryPolicyResolver, } from "./types.js";
2
+ export { encodeWakeup, decodeWakeup, supportsChangeCursor } from "./types.js";
3
+ export { channelName, parseChannel, channelFor, authorizeSubscription, } from "./channel.js";
4
+ export { CalmDeliveryResolver, ALWAYS_DELIVER_TYPES, } from "./delivery-policy.js";
5
+ export { InMemorySettingStore } from "./setting-store.js";
6
+ export { PollTransport } from "./poll-transport.js";
7
+ export { NoopRealtimeTransport } from "./no-op-transport.js";
8
+ import type { RealtimeTransport } from "./types.js";
9
+ /**
10
+ * Consuming app (Skybber) calls this at startup with its concrete transport
11
+ * (e.g. AppSyncEventsTransport). MUST run before buildEnv-consumers serve.
12
+ */
13
+ export declare function setRealtimeProvider(transport: RealtimeTransport): void;
14
+ /**
15
+ * Returns the injected transport if a provider was registered, else the
16
+ * supplied fallback. `buildEnv` calls this with the default Poll/Noop transport.
17
+ */
18
+ export declare function resolveRealtimeTransport(fallback: RealtimeTransport): RealtimeTransport;
19
+ /** Test-only: clear the injected provider so tests don't leak across cases. */
20
+ export declare function __resetRealtimeProviderForTests(): void;
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/realtime/index.ts"],"names":[],"mappings":"AAQA,YAAY,EAEV,OAAO,EACP,WAAW,EACX,SAAS,EAET,gBAAgB,EAEhB,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAEhB,cAAc,EAEd,aAAa,EACb,SAAS,EACT,YAAY,EAEZ,kBAAkB,EAClB,iBAAiB,EAEjB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE9E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,UAAU,EACV,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAWpD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAEtE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,iBAAiB,GAC1B,iBAAiB,CAEnB;AAED,+EAA+E;AAC/E,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD"}
@@ -0,0 +1,39 @@
1
+ // CONTRACT: stable — coordinate changes. See types.ts banner.
2
+ //
3
+ // Public barrel for the RealtimeTransport seam — the ONLY import path consumers
4
+ // use (published as `@de-otio/trellis/realtime`). Re-exports the frozen types,
5
+ // the channel helpers, the ports + defaults, the two in-core transports, and
6
+ // the provider-injection hook a consuming app (Skybber) uses to plug in its
7
+ // AppSyncEventsTransport WITHOUT core importing any AWS SDK.
8
+ export { encodeWakeup, decodeWakeup, supportsChangeCursor } from "./types.js";
9
+ export { channelName, parseChannel, channelFor, authorizeSubscription, } from "./channel.js";
10
+ export { CalmDeliveryResolver, ALWAYS_DELIVER_TYPES, } from "./delivery-policy.js";
11
+ export { InMemorySettingStore } from "./setting-store.js";
12
+ export { PollTransport } from "./poll-transport.js";
13
+ export { NoopRealtimeTransport } from "./no-op-transport.js";
14
+ // ---------------------------------------------------------------------------
15
+ // Provider-injection hook (mirrors registerExtension). A consuming app calls
16
+ // setRealtimeProvider() at startup, BEFORE buildEnv-consumers serve, with its
17
+ // concrete transport. resolveRealtimeTransport() returns the injected transport
18
+ // if present, else the supplied fallback (the core Poll/Noop default).
19
+ // ---------------------------------------------------------------------------
20
+ let injected;
21
+ /**
22
+ * Consuming app (Skybber) calls this at startup with its concrete transport
23
+ * (e.g. AppSyncEventsTransport). MUST run before buildEnv-consumers serve.
24
+ */
25
+ export function setRealtimeProvider(transport) {
26
+ injected = transport;
27
+ }
28
+ /**
29
+ * Returns the injected transport if a provider was registered, else the
30
+ * supplied fallback. `buildEnv` calls this with the default Poll/Noop transport.
31
+ */
32
+ export function resolveRealtimeTransport(fallback) {
33
+ return injected ?? fallback;
34
+ }
35
+ /** Test-only: clear the injected provider so tests don't leak across cases. */
36
+ export function __resetRealtimeProviderForTests() {
37
+ injected = undefined;
38
+ }
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/realtime/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,6EAA6E;AAC7E,4EAA4E;AAC5E,6DAA6D;AA6B7D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE9E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,UAAU,EACV,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,gFAAgF;AAChF,uEAAuE;AACvE,8EAA8E;AAE9E,IAAI,QAAuC,CAAC;AAE5C;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAA4B;IAC9D,QAAQ,GAAG,SAAS,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA2B;IAE3B,OAAO,QAAQ,IAAI,QAAQ,CAAC;AAC9B,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,+BAA+B;IAC7C,QAAQ,GAAG,SAAS,CAAC;AACvB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Channel, DeliveryPolicyResolver, DeliveryResult, DeliveryTarget, EncryptedBlob, PutResult, RealtimeTransport } from "./types.js";
2
+ export declare class NoopRealtimeTransport implements RealtimeTransport {
3
+ private readonly policy;
4
+ readonly kind: "noop";
5
+ constructor(policy: DeliveryPolicyResolver);
6
+ deliver(target: DeliveryTarget, channel: Channel, _payload: Uint8Array): Promise<DeliveryResult>;
7
+ getSetting(_userId: string, _namespace: string): Promise<EncryptedBlob | null>;
8
+ putSetting(_userId: string, _namespace: string, _blob: EncryptedBlob, _expectVersion: number): Promise<PutResult>;
9
+ }
10
+ //# sourceMappingURL=no-op-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-op-transport.d.ts","sourceRoot":"","sources":["../../../src/lib/realtime/no-op-transport.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,OAAO,EAEP,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,aAAa,EACb,SAAS,EACT,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAepB,qBAAa,qBAAsB,YAAW,iBAAiB;IAGjD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;gBAEH,MAAM,EAAE,sBAAsB;IAErD,OAAO,CACX,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,UAAU,GACnB,OAAO,CAAC,cAAc,CAAC;IAepB,UAAU,CACd,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAI1B,UAAU,CACd,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,aAAa,EACpB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,SAAS,CAAC;CAGtB"}
@@ -0,0 +1,44 @@
1
+ // CONTRACT-adjacent — the CI transport. See types.ts banner.
2
+ //
3
+ // NoopRealtimeTransport: the same shape as PollTransport but with NO store and
4
+ // NO wire. It still runs the policy fence inside deliver() (so the fence-runs-
5
+ // on-every-transport invariant holds), then drops. getSetting/putSetting are
6
+ // inert (no store). Used in tests/CI where neither a store nor a socket exists.
7
+ function fenceContextFor(target, channel) {
8
+ const type = channel.kind === "safety" ? "SAFETY_ALERT" : "SYSTEM";
9
+ return {
10
+ type,
11
+ recipientUserId: target.userId,
12
+ tenantId: target.tenantId,
13
+ now: new Date(),
14
+ };
15
+ }
16
+ export class NoopRealtimeTransport {
17
+ policy;
18
+ kind = "noop";
19
+ constructor(policy) {
20
+ this.policy = policy;
21
+ }
22
+ async deliver(target, channel, _payload) {
23
+ // Best-effort: a transport-internal fault (e.g. a throwing resolver) is
24
+ // caught and surfaced as transport_error, never a reject that could roll
25
+ // back a persisted write (frozen contract §2.3).
26
+ try {
27
+ const decision = this.policy.decide(fenceContextFor(target, channel));
28
+ if (!decision.deliver) {
29
+ return { delivered: false, reason: "policy_denied" };
30
+ }
31
+ return { delivered: false, reason: "no_transport" };
32
+ }
33
+ catch {
34
+ return { delivered: false, reason: "transport_error" };
35
+ }
36
+ }
37
+ async getSetting(_userId, _namespace) {
38
+ return null;
39
+ }
40
+ async putSetting(_userId, _namespace, _blob, _expectVersion) {
41
+ return { ok: false, reason: "not_found", current: null };
42
+ }
43
+ }
44
+ //# sourceMappingURL=no-op-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-op-transport.js","sourceRoot":"","sources":["../../../src/lib/realtime/no-op-transport.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAahF,SAAS,eAAe,CACtB,MAAsB,EACtB,OAAgB;IAEhB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnE,OAAO;QACL,IAAI;QACJ,eAAe,EAAE,MAAM,CAAC,MAAM;QAC9B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,IAAI,IAAI,EAAE;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,qBAAqB;IAGH;IAFpB,IAAI,GAAG,MAAe,CAAC;IAEhC,YAA6B,MAA8B;QAA9B,WAAM,GAAN,MAAM,CAAwB;IAAG,CAAC;IAE/D,KAAK,CAAC,OAAO,CACX,MAAsB,EACtB,OAAgB,EAChB,QAAoB;QAEpB,wEAAwE;QACxE,yEAAyE;QACzE,iDAAiD;QACjD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;YACvD,CAAC;YACD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;QACzD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CACd,OAAe,EACf,UAAkB;QAElB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,UAAU,CACd,OAAe,EACf,UAAkB,EAClB,KAAoB,EACpB,cAAsB;QAEtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3D,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import type { Channel, DeliveryPolicyResolver, DeliveryResult, DeliveryTarget, EncryptedBlob, PutResult, RealtimeTransport, SettingStore } from "./types.js";
2
+ export declare class PollTransport implements RealtimeTransport {
3
+ private readonly store;
4
+ private readonly policy;
5
+ readonly kind: "poll";
6
+ constructor(store: SettingStore, policy: DeliveryPolicyResolver);
7
+ deliver(target: DeliveryTarget, channel: Channel, _payload: Uint8Array): Promise<DeliveryResult>;
8
+ getSetting(userId: string, namespace: string): Promise<EncryptedBlob | null>;
9
+ putSetting(userId: string, namespace: string, blob: EncryptedBlob, expectVersion: number): Promise<PutResult>;
10
+ }
11
+ //# sourceMappingURL=poll-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poll-transport.d.ts","sourceRoot":"","sources":["../../../src/lib/realtime/poll-transport.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,OAAO,EAEP,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,YAAY,EACb,MAAM,YAAY,CAAC;AA0BpB,qBAAa,aAAc,YAAW,iBAAiB;IAInD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;gBAGb,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,sBAAsB;IAG3C,OAAO,CACX,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,UAAU,GACnB,OAAO,CAAC,cAAc,CAAC;IAmB1B,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAI5E,UAAU,CACR,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,aAAa,EACnB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,SAAS,CAAC;CAGtB"}
@@ -0,0 +1,68 @@
1
+ // CONTRACT-adjacent — the default transport. See types.ts banner.
2
+ //
3
+ // PollTransport makes core runnable and testable with NO realtime infra. It is
4
+ // a correctness default, explicitly NOT the scale answer.
5
+ //
6
+ // deliver() -> runs the policy fence, then NO-OPs the wire send and returns
7
+ // { delivered: false, reason: "no_transport" } (clients poll;
8
+ // the side-effecting persistence — the Notification row / the
9
+ // setting version bump — is what the next poll observes). The
10
+ // fence still runs so swapping in AppSync changes the pipe, not
11
+ // a single call site.
12
+ // getSetting / putSetting -> delegate to the injected SettingStore (the real
13
+ // REST-backed sync path).
14
+ /**
15
+ * Build the `DeliveryContext` the policy fence needs from a `deliver()` call.
16
+ * PollTransport has no notification metadata at the wire boundary (the floor
17
+ * decision was already made by the caller for persistence), so it constructs a
18
+ * minimal, fence-running context. The interface keeps payloads opaque, so the
19
+ * transport derives only routing-level inputs.
20
+ */
21
+ function fenceContextFor(target, channel) {
22
+ // Map the channel kind back onto a NotificationType-shaped floor input: the
23
+ // "safety" kind is critical-always, everything else is best-effort. We do not
24
+ // have the original NotificationType here, so we synthesize the floor-relevant
25
+ // signal: a "safety" channel must never be suppressed.
26
+ const type = channel.kind === "safety" ? "SAFETY_ALERT" : "SYSTEM";
27
+ return {
28
+ type,
29
+ recipientUserId: target.userId,
30
+ tenantId: target.tenantId,
31
+ now: new Date(),
32
+ };
33
+ }
34
+ export class PollTransport {
35
+ store;
36
+ policy;
37
+ kind = "poll";
38
+ constructor(store, policy) {
39
+ this.store = store;
40
+ this.policy = policy;
41
+ }
42
+ async deliver(target, channel, _payload) {
43
+ // deliver() is BEST-EFFORT: it MUST NOT reject in a way that could roll back
44
+ // a persisted write upstream. Any internal fault (e.g. a throwing resolver)
45
+ // is caught and surfaced as transport_error (frozen contract §2.3 + the
46
+ // realtime-transport.ts binding rules).
47
+ try {
48
+ // The policy fence runs on EVERY transport, even the no-op one.
49
+ const decision = this.policy.decide(fenceContextFor(target, channel));
50
+ if (!decision.deliver) {
51
+ return { delivered: false, reason: "policy_denied" };
52
+ }
53
+ // Poll model: there is no socket. The client learns of the change on its
54
+ // next poll, so the wire send is a deliberate no-op.
55
+ return { delivered: false, reason: "no_transport" };
56
+ }
57
+ catch {
58
+ return { delivered: false, reason: "transport_error" };
59
+ }
60
+ }
61
+ getSetting(userId, namespace) {
62
+ return this.store.get(userId, namespace);
63
+ }
64
+ putSetting(userId, namespace, blob, expectVersion) {
65
+ return this.store.put(userId, namespace, blob, expectVersion);
66
+ }
67
+ }
68
+ //# sourceMappingURL=poll-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poll-transport.js","sourceRoot":"","sources":["../../../src/lib/realtime/poll-transport.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,+EAA+E;AAC/E,0DAA0D;AAC1D,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,sCAAsC;AACtC,+EAA+E;AAC/E,0CAA0C;AAc1C;;;;;;GAMG;AACH,SAAS,eAAe,CACtB,MAAsB,EACtB,OAAgB;IAEhB,4EAA4E;IAC5E,8EAA8E;IAC9E,+EAA+E;IAC/E,uDAAuD;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnE,OAAO;QACL,IAAI;QACJ,eAAe,EAAE,MAAM,CAAC,MAAM;QAC9B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,IAAI,IAAI,EAAE;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,aAAa;IAIL;IACA;IAJV,IAAI,GAAG,MAAe,CAAC;IAEhC,YACmB,KAAmB,EACnB,MAA8B;QAD9B,UAAK,GAAL,KAAK,CAAc;QACnB,WAAM,GAAN,MAAM,CAAwB;IAC9C,CAAC;IAEJ,KAAK,CAAC,OAAO,CACX,MAAsB,EACtB,OAAgB,EAChB,QAAoB;QAEpB,6EAA6E;QAC7E,4EAA4E;QAC5E,wEAAwE;QACxE,wCAAwC;QACxC,IAAI,CAAC;YACH,gEAAgE;YAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;YACvD,CAAC;YACD,yEAAyE;YACzE,qDAAqD;YACrD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;QACzD,CAAC;IACH,CAAC;IAED,UAAU,CAAC,MAAc,EAAE,SAAiB;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED,UAAU,CACR,MAAc,EACd,SAAiB,EACjB,IAAmB,EACnB,aAAqB;QAErB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;IAChE,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ import type { Logger } from "../logger.js";
2
+ import type { ChannelKind, RealtimeTransport } from "./types.js";
3
+ /** The kinds WS4 routes a content-free notification wakeup onto. */
4
+ export type WakeupKind = Extract<ChannelKind, "wakeup" | "safety">;
5
+ export interface PushNotifierInput {
6
+ /** Server-resolved recipient. */
7
+ target: {
8
+ userId: string;
9
+ tenantId: string;
10
+ };
11
+ /**
12
+ * Channel kind: ALWAYS_DELIVER notifications route to "safety" (the floor
13
+ * channel), everything else to "wakeup". Constrained to the two content-free
14
+ * kinds WS4 owns — there is no overload that accepts "message"/"thread".
15
+ */
16
+ kind: WakeupKind;
17
+ }
18
+ /**
19
+ * Build the content-free wakeup payload for a notification. The envelope is the
20
+ * frozen WS1 `WakeupEnvelope` and carries NO notification content — only the
21
+ * envelope version and the channel kind. There is deliberately no `changeToken`
22
+ * for notification wakeups (that field is the setting_sync version pointer); a
23
+ * notification wakeup says only "something changed on this surface; refetch".
24
+ */
25
+ export declare function buildNotificationWakeup(kind: WakeupKind): Uint8Array;
26
+ /**
27
+ * Relay a content-free wakeup over the realtime transport, best-effort.
28
+ *
29
+ * Resolves to `true` if the transport reported a delivery, `false` otherwise
30
+ * (policy-denied, no transport, transport error, or a thrown transport). NEVER
31
+ * throws — the caller's persisted write is durable regardless.
32
+ */
33
+ export declare class PushNotifier {
34
+ private readonly transport;
35
+ private readonly logger;
36
+ constructor(transport: RealtimeTransport, logger: Logger);
37
+ notify(input: PushNotifierInput): Promise<boolean>;
38
+ }
39
+ //# sourceMappingURL=push-notifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-notifier.d.ts","sourceRoot":"","sources":["../../../src/lib/realtime/push-notifier.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAkB,MAAM,YAAY,CAAC;AAEjF,oEAAoE;AACpE,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEnE,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C;;;;OAIG;IACH,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAGpE;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,MAAM;IAG3B,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;CA8BzD"}
@@ -0,0 +1,76 @@
1
+ // WS4 — content-free push consumer.
2
+ //
3
+ // PushNotifier is the ONE place that turns a "deliver" decision into a wire
4
+ // wakeup. It exists so `notification-handler.ts` stays slim and so the
5
+ // content-free guarantee is structural, not a per-call-site discipline:
6
+ //
7
+ // 1. The payload is built ONLY via `encodeWakeup()` (the frozen WS1 envelope).
8
+ // WS4 is FORBIDDEN by the contract from constructing arbitrary Uint8Array
9
+ // for wakeup/setting_sync/safety kinds — there is no code path here that
10
+ // can put a title/body/data on the wire (types.ts §2.4).
11
+ // 2. The channel is built ONLY via `channelFor()` — tenant- and user-scoped,
12
+ // server-resolved, never client-asserted.
13
+ // 3. `transport.deliver()` is BEST-EFFORT: a transport throw is caught and
14
+ // logged, NEVER rethrown, so it can never roll back the already-persisted
15
+ // Notification row. Polling remains the floor.
16
+ //
17
+ // The policy fence (CalmDeliveryResolver floor) runs in TWO places by design:
18
+ // the caller gates on its decision (so a deferred/blocked/preference-off
19
+ // notification never reaches here), AND the transport re-runs the fence inside
20
+ // `deliver()`. PushNotifier itself does not re-decide — it relays the decision
21
+ // the caller already made onto the correct channel kind.
22
+ import { channelFor } from "./channel.js";
23
+ import { encodeWakeup } from "./types.js";
24
+ /**
25
+ * Build the content-free wakeup payload for a notification. The envelope is the
26
+ * frozen WS1 `WakeupEnvelope` and carries NO notification content — only the
27
+ * envelope version and the channel kind. There is deliberately no `changeToken`
28
+ * for notification wakeups (that field is the setting_sync version pointer); a
29
+ * notification wakeup says only "something changed on this surface; refetch".
30
+ */
31
+ export function buildNotificationWakeup(kind) {
32
+ const envelope = { v: 1, kind };
33
+ return encodeWakeup(envelope);
34
+ }
35
+ /**
36
+ * Relay a content-free wakeup over the realtime transport, best-effort.
37
+ *
38
+ * Resolves to `true` if the transport reported a delivery, `false` otherwise
39
+ * (policy-denied, no transport, transport error, or a thrown transport). NEVER
40
+ * throws — the caller's persisted write is durable regardless.
41
+ */
42
+ export class PushNotifier {
43
+ transport;
44
+ logger;
45
+ constructor(transport, logger) {
46
+ this.transport = transport;
47
+ this.logger = logger;
48
+ }
49
+ async notify(input) {
50
+ const { target, kind } = input;
51
+ const channel = channelFor(kind, {
52
+ tenantId: target.tenantId,
53
+ userId: target.userId,
54
+ });
55
+ const payload = buildNotificationWakeup(kind);
56
+ try {
57
+ const result = await this.transport.deliver({ userId: target.userId, tenantId: target.tenantId }, channel, payload);
58
+ if (!result.delivered) {
59
+ // Not an error — poll/no-transport/policy are normal outcomes. Logged
60
+ // at debug so the absence of a push is observable without noise.
61
+ this.logger.debug("realtime wakeup not delivered", {
62
+ reason: result.reason,
63
+ kind,
64
+ });
65
+ }
66
+ return result.delivered;
67
+ }
68
+ catch (err) {
69
+ // BEST-EFFORT: a transport hiccup must never surface to the caller. The
70
+ // notification row is already persisted; the next poll delivers it.
71
+ this.logger.warn("realtime wakeup deliver threw (non-fatal)", err);
72
+ return false;
73
+ }
74
+ }
75
+ }
76
+ //# sourceMappingURL=push-notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-notifier.js","sourceRoot":"","sources":["../../../src/lib/realtime/push-notifier.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,wEAAwE;AACxE,EAAE;AACF,iFAAiF;AACjF,+EAA+E;AAC/E,8EAA8E;AAC9E,8DAA8D;AAC9D,+EAA+E;AAC/E,+CAA+C;AAC/C,6EAA6E;AAC7E,+EAA+E;AAC/E,oDAAoD;AACpD,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,+EAA+E;AAC/E,+EAA+E;AAC/E,yDAAyD;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiB1C;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAgB;IACtD,MAAM,QAAQ,GAAmB,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;IAChD,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IAEJ;IACA;IAFnB,YACmB,SAA4B,EAC5B,MAAc;QADd,cAAS,GAAT,SAAS,CAAmB;QAC5B,WAAM,GAAN,MAAM,CAAQ;IAC9B,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,KAAwB;QACnC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;QAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE;YAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CACzC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EACpD,OAAO,EACP,OAAO,CACR,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBACtB,sEAAsE;gBACtE,iEAAiE;gBACjE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE;oBACjD,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;YACD,OAAO,MAAM,CAAC,SAAS,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,wEAAwE;YACxE,oEAAoE;YACpE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;YACnE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export type { RealtimeTransport, DeliveryPolicyResolver, DeliveryTarget, DeliveryResult, Channel, EncryptedBlob, PutResult, SettingStore, } from "./types.js";
2
+ //# sourceMappingURL=realtime-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-transport.d.ts","sourceRoot":"","sources":["../../../src/lib/realtime/realtime-transport.ts"],"names":[],"mappings":"AAsBA,YAAY,EACV,iBAAiB,EACjB,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,OAAO,EACP,aAAa,EACb,SAAS,EACT,YAAY,GACb,MAAM,YAAY,CAAC"}