deepline 0.3.113 → 0.3.114

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 (48) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +3 -1
  2. package/dist/bundling-sources/sdk/src/compat.ts +167 -11
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/sdk/src/skills-version.ts +27 -1
  5. package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +6 -2
  6. package/dist/bundling-sources/shared_libs/observability/queue-health.ts +291 -6
  7. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +24 -24
  8. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +2 -0
  9. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +29 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/admission-transport-policy.ts +91 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +2 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/direct-admission-deadline.ts +34 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +1 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +325 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/play-admission-outcome.ts +134 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +13 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +4 -1
  18. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +13 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-admission-probe.ts +32 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-identity.ts +28 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-cron-fire-task.ts +100 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +313 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +111 -3
  25. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +16 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +67 -8
  27. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1394 -22
  28. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +74 -13
  29. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +79 -15
  30. package/dist/bundling-sources/shared_libs/play-runtime/webhook-receipt-retry.ts +21 -21
  31. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +4 -1
  32. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +64 -0
  33. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +1 -1
  34. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +20 -1
  35. package/dist/bundling-sources/shared_libs/security/receipt-admission-token.ts +224 -0
  36. package/dist/cli/index.js +574 -114
  37. package/dist/cli/index.mjs +592 -133
  38. package/dist/index.d.mts +54 -1
  39. package/dist/index.d.ts +54 -1
  40. package/dist/index.js +8 -3
  41. package/dist/index.mjs +8 -3
  42. package/dist/install-integrity.json +7 -0
  43. package/dist/plays/bundle-play-file.mjs +1 -1
  44. package/dist/release.d.mts +1 -1
  45. package/dist/release.d.ts +1 -1
  46. package/dist/release.js +1 -1
  47. package/dist/release.mjs +1 -1
  48. package/package.json +1 -1
@@ -0,0 +1,224 @@
1
+ /**
2
+ * HMAC capabilities for a Convex-owned receipt to call its corresponding
3
+ * Vercel private adapter. This lives in a package because Convex is a separate
4
+ * workspace: it must mint the same short-lived capability that the app
5
+ * verifies, without importing application source across the workspace seam.
6
+ */
7
+ const TOKEN_VERSION = 1 as const;
8
+ const TOKEN_TTL_SECONDS = 5 * 60;
9
+ const TOKEN_ISSUER = 'deepline.internal' as const;
10
+ const TOKEN_DERIVATION_LABEL = 'deepline:internal-bootstrap-token:v1';
11
+
12
+ const PLAY_WEBHOOK_RECEIPT_AUDIENCE =
13
+ 'deepline.play_webhook_receipt.admission' as const;
14
+ const PLAY_WEBHOOK_RECEIPT_PURPOSE = 'play_webhook_receipt_admission' as const;
15
+ const PLAY_WEBHOOK_RECEIPT_BATCH_AUDIENCE =
16
+ 'deepline.play_webhook_receipt.batch_admission' as const;
17
+ const PLAY_WEBHOOK_RECEIPT_BATCH_PURPOSE =
18
+ 'play_webhook_receipt_batch_admission' as const;
19
+ const PLAY_WEBHOOK_RECEIPT_LARGE_BATCH_PURPOSE =
20
+ 'play_webhook_receipt_large_batch_admission' as const;
21
+ export const PLAY_WEBHOOK_RECEIPT_LARGE_BATCH_MAX_RECEIPTS = 1_024;
22
+ const PLAY_TRIGGER_EVENT_AUDIENCE =
23
+ 'deepline.play_trigger_event.admission' as const;
24
+ const PLAY_TRIGGER_EVENT_PURPOSE = 'play_trigger_event_admission' as const;
25
+ const SIGNAL_RADAR_INBOUND_RECEIPT_AUDIENCE =
26
+ 'deepline.signal_radar_inbound_receipt.process' as const;
27
+ const SIGNAL_RADAR_INBOUND_RECEIPT_PURPOSE =
28
+ 'signal_radar_inbound_receipt_process' as const;
29
+
30
+ function rootSecret(): string {
31
+ const secret = process.env.BETTER_AUTH_SECRET;
32
+ if (!secret) throw new Error('BETTER_AUTH_SECRET is not set.');
33
+ return `${secret}:${TOKEN_DERIVATION_LABEL}`;
34
+ }
35
+
36
+ function bytesToBase64(bytes: Uint8Array): string {
37
+ if (typeof Buffer !== 'undefined') {
38
+ return Buffer.from(bytes).toString('base64');
39
+ }
40
+ let binary = '';
41
+ for (const byte of bytes) binary += String.fromCharCode(byte);
42
+ return btoa(binary);
43
+ }
44
+
45
+ function toBase64Url(bytes: Uint8Array): string {
46
+ return bytesToBase64(bytes)
47
+ .replace(/\+/g, '-')
48
+ .replace(/\//g, '_')
49
+ .replace(/=+$/g, '');
50
+ }
51
+
52
+ function encodeJson(value: unknown): string {
53
+ return toBase64Url(new TextEncoder().encode(JSON.stringify(value)));
54
+ }
55
+
56
+ async function sign(value: string): Promise<string> {
57
+ const key = await crypto.subtle.importKey(
58
+ 'raw',
59
+ new TextEncoder().encode(rootSecret()),
60
+ { name: 'HMAC', hash: 'SHA-256' },
61
+ false,
62
+ ['sign'],
63
+ );
64
+ return toBase64Url(
65
+ new Uint8Array(
66
+ await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(value)),
67
+ ),
68
+ );
69
+ }
70
+
71
+ async function mint(claims: Record<string, unknown>): Promise<string> {
72
+ const header = encodeJson({ alg: 'HS256', typ: 'JWT' });
73
+ const payload = encodeJson(claims);
74
+ const signingInput = `${header}.${payload}`;
75
+ return `${signingInput}.${await sign(signingInput)}`;
76
+ }
77
+
78
+ /**
79
+ * Bind a large request body to its capability without putting up to 1,024
80
+ * receipt IDs in an HTTP header. JSON preserves order and length, so this is
81
+ * an exact ordered set rather than a lossy collection fingerprint.
82
+ */
83
+ export async function hashPlayWebhookReceiptBatchIds(
84
+ receiptIds: readonly string[],
85
+ ): Promise<string> {
86
+ return toBase64Url(
87
+ new Uint8Array(
88
+ await crypto.subtle.digest(
89
+ 'SHA-256',
90
+ new TextEncoder().encode(JSON.stringify(receiptIds)),
91
+ ),
92
+ ),
93
+ );
94
+ }
95
+
96
+ function assertUniqueReceiptIds(
97
+ receiptIds: readonly string[],
98
+ maxLength: number,
99
+ label: string,
100
+ ) {
101
+ if (receiptIds.length < 1 || receiptIds.length > maxLength) {
102
+ throw new Error(
103
+ `${label} must contain between 1 and ${maxLength} receipts.`,
104
+ );
105
+ }
106
+ if (
107
+ receiptIds.some(
108
+ (receiptId) =>
109
+ typeof receiptId !== 'string' || receiptId.trim().length === 0,
110
+ )
111
+ ) {
112
+ throw new Error(`${label} receipt IDs must be non-empty strings.`);
113
+ }
114
+ if (new Set(receiptIds).size !== receiptIds.length) {
115
+ throw new Error(`${label} receipt IDs must be unique.`);
116
+ }
117
+ }
118
+
119
+ export async function mintPlayWebhookReceiptAdmissionToken(input: {
120
+ orgId: string;
121
+ receiptId: string;
122
+ nowMs?: number;
123
+ }): Promise<string> {
124
+ const issuedAt = Math.floor((input.nowMs ?? Date.now()) / 1000);
125
+ return await mint({
126
+ v: TOKEN_VERSION,
127
+ iss: TOKEN_ISSUER,
128
+ aud: PLAY_WEBHOOK_RECEIPT_AUDIENCE,
129
+ purpose: PLAY_WEBHOOK_RECEIPT_PURPOSE,
130
+ org_id: input.orgId,
131
+ receipt_id: input.receiptId,
132
+ sub: 'play_webhook_receipt_dispatcher',
133
+ iat: issuedAt,
134
+ exp: issuedAt + TOKEN_TTL_SECONDS,
135
+ });
136
+ }
137
+
138
+ /** Capability for one Convex-owned, single-workspace receipt batch. */
139
+ export async function mintPlayWebhookReceiptBatchAdmissionToken(input: {
140
+ orgId: string;
141
+ receiptIds: readonly string[];
142
+ nowMs?: number;
143
+ }): Promise<string> {
144
+ assertUniqueReceiptIds(input.receiptIds, 32, 'Webhook admission batch');
145
+ const issuedAt = Math.floor((input.nowMs ?? Date.now()) / 1000);
146
+ return await mint({
147
+ v: TOKEN_VERSION,
148
+ iss: TOKEN_ISSUER,
149
+ aud: PLAY_WEBHOOK_RECEIPT_BATCH_AUDIENCE,
150
+ purpose: PLAY_WEBHOOK_RECEIPT_BATCH_PURPOSE,
151
+ org_id: input.orgId,
152
+ receipt_ids: [...input.receiptIds],
153
+ sub: 'play_webhook_receipt_batch_dispatcher',
154
+ iat: issuedAt,
155
+ exp: issuedAt + TOKEN_TTL_SECONDS,
156
+ });
157
+ }
158
+
159
+ /**
160
+ * Capability for one large, exact receipt collection. Its digest keeps the
161
+ * signed header small enough for Vercel while the body still carries every
162
+ * independently durable source identity.
163
+ */
164
+ export async function mintPlayWebhookReceiptLargeBatchAdmissionToken(input: {
165
+ orgId: string;
166
+ receiptIds: readonly string[];
167
+ nowMs?: number;
168
+ }): Promise<string> {
169
+ assertUniqueReceiptIds(
170
+ input.receiptIds,
171
+ PLAY_WEBHOOK_RECEIPT_LARGE_BATCH_MAX_RECEIPTS,
172
+ 'Webhook large admission batch',
173
+ );
174
+ const issuedAt = Math.floor((input.nowMs ?? Date.now()) / 1000);
175
+ return await mint({
176
+ v: TOKEN_VERSION,
177
+ iss: TOKEN_ISSUER,
178
+ aud: PLAY_WEBHOOK_RECEIPT_BATCH_AUDIENCE,
179
+ purpose: PLAY_WEBHOOK_RECEIPT_LARGE_BATCH_PURPOSE,
180
+ org_id: input.orgId,
181
+ receipt_ids_sha256: await hashPlayWebhookReceiptBatchIds(input.receiptIds),
182
+ sub: 'play_webhook_receipt_large_batch_dispatcher',
183
+ iat: issuedAt,
184
+ exp: issuedAt + TOKEN_TTL_SECONDS,
185
+ });
186
+ }
187
+
188
+ export async function mintPlayTriggerEventAdmissionToken(input: {
189
+ orgId: string;
190
+ eventId: string;
191
+ nowMs?: number;
192
+ }): Promise<string> {
193
+ const issuedAt = Math.floor((input.nowMs ?? Date.now()) / 1000);
194
+ return await mint({
195
+ v: TOKEN_VERSION,
196
+ iss: TOKEN_ISSUER,
197
+ aud: PLAY_TRIGGER_EVENT_AUDIENCE,
198
+ purpose: PLAY_TRIGGER_EVENT_PURPOSE,
199
+ org_id: input.orgId,
200
+ event_id: input.eventId,
201
+ sub: 'play_trigger_event_dispatcher',
202
+ iat: issuedAt,
203
+ exp: issuedAt + TOKEN_TTL_SECONDS,
204
+ });
205
+ }
206
+
207
+ export async function mintSignalRadarInboundReceiptToken(input: {
208
+ orgId: string;
209
+ receiptId: string;
210
+ nowMs?: number;
211
+ }): Promise<string> {
212
+ const issuedAt = Math.floor((input.nowMs ?? Date.now()) / 1000);
213
+ return await mint({
214
+ v: TOKEN_VERSION,
215
+ iss: TOKEN_ISSUER,
216
+ aud: SIGNAL_RADAR_INBOUND_RECEIPT_AUDIENCE,
217
+ purpose: SIGNAL_RADAR_INBOUND_RECEIPT_PURPOSE,
218
+ org_id: input.orgId,
219
+ receipt_id: input.receiptId,
220
+ sub: 'signal_radar_inbound_receipt_dispatcher',
221
+ iat: issuedAt,
222
+ exp: issuedAt + TOKEN_TTL_SECONDS,
223
+ });
224
+ }