deepline 0.1.12 → 0.1.19

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 (80) hide show
  1. package/README.md +14 -6
  2. package/dist/cli/index.js +1298 -711
  3. package/dist/cli/index.mjs +1294 -707
  4. package/dist/index.d.mts +199 -23
  5. package/dist/index.d.ts +199 -23
  6. package/dist/index.js +219 -13
  7. package/dist/index.mjs +219 -13
  8. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +68 -12
  9. package/dist/repo/apps/play-runner-workers/src/entry.ts +241 -51
  10. package/dist/repo/sdk/src/client.ts +237 -0
  11. package/dist/repo/sdk/src/config.ts +125 -8
  12. package/dist/repo/sdk/src/http.ts +10 -2
  13. package/dist/repo/sdk/src/play.ts +19 -36
  14. package/dist/repo/sdk/src/plays/bundle-play-file.ts +22 -8
  15. package/dist/repo/sdk/src/plays/local-file-discovery.ts +207 -160
  16. package/dist/repo/sdk/src/types.ts +25 -0
  17. package/dist/repo/sdk/src/version.ts +2 -2
  18. package/dist/repo/shared_libs/play-runtime/tool-result.ts +237 -145
  19. package/dist/repo/shared_libs/plays/bundling/index.ts +206 -229
  20. package/dist/repo/shared_libs/plays/dataset.ts +28 -0
  21. package/package.json +5 -4
  22. package/dist/cli/index.js.map +0 -1
  23. package/dist/cli/index.mjs.map +0 -1
  24. package/dist/index.js.map +0 -1
  25. package/dist/index.mjs.map +0 -1
  26. package/dist/repo/apps/play-runner-workers/src/runtime/README.md +0 -21
  27. package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +0 -177
  28. package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +0 -52
  29. package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -100
  30. package/dist/repo/sdk/src/cli/commands/auth.ts +0 -500
  31. package/dist/repo/sdk/src/cli/commands/billing.ts +0 -188
  32. package/dist/repo/sdk/src/cli/commands/csv.ts +0 -123
  33. package/dist/repo/sdk/src/cli/commands/db.ts +0 -119
  34. package/dist/repo/sdk/src/cli/commands/feedback.ts +0 -40
  35. package/dist/repo/sdk/src/cli/commands/org.ts +0 -117
  36. package/dist/repo/sdk/src/cli/commands/play.ts +0 -3441
  37. package/dist/repo/sdk/src/cli/commands/tools.ts +0 -687
  38. package/dist/repo/sdk/src/cli/dataset-stats.ts +0 -415
  39. package/dist/repo/sdk/src/cli/index.ts +0 -148
  40. package/dist/repo/sdk/src/cli/progress.ts +0 -149
  41. package/dist/repo/sdk/src/cli/skills-sync.ts +0 -141
  42. package/dist/repo/sdk/src/cli/trace.ts +0 -61
  43. package/dist/repo/sdk/src/cli/utils.ts +0 -145
  44. package/dist/repo/sdk/src/compat.ts +0 -77
  45. package/dist/repo/shared_libs/observability/node-tracing.ts +0 -129
  46. package/dist/repo/shared_libs/observability/tracing.ts +0 -98
  47. package/dist/repo/shared_libs/play-runtime/context.ts +0 -4242
  48. package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +0 -250
  49. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +0 -725
  50. package/dist/repo/shared_libs/play-runtime/dataset-id.ts +0 -10
  51. package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +0 -304
  52. package/dist/repo/shared_libs/play-runtime/db-session.ts +0 -462
  53. package/dist/repo/shared_libs/play-runtime/live-events.ts +0 -214
  54. package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +0 -50
  55. package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +0 -114
  56. package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +0 -158
  57. package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +0 -172
  58. package/dist/repo/shared_libs/play-runtime/protocol.ts +0 -121
  59. package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +0 -42
  60. package/dist/repo/shared_libs/play-runtime/result-normalization.ts +0 -33
  61. package/dist/repo/shared_libs/play-runtime/runtime-api.ts +0 -1873
  62. package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +0 -2
  63. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -201
  64. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +0 -48
  65. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +0 -84
  66. package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +0 -147
  67. package/dist/repo/shared_libs/play-runtime/suspension.ts +0 -68
  68. package/dist/repo/shared_libs/play-runtime/tracing.ts +0 -31
  69. package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +0 -75
  70. package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +0 -140
  71. package/dist/repo/shared_libs/plays/artifact-transport.ts +0 -14
  72. package/dist/repo/shared_libs/plays/artifact-types.ts +0 -49
  73. package/dist/repo/shared_libs/plays/compiler-manifest.ts +0 -186
  74. package/dist/repo/shared_libs/plays/definition.ts +0 -264
  75. package/dist/repo/shared_libs/plays/file-refs.ts +0 -11
  76. package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +0 -206
  77. package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +0 -164
  78. package/dist/repo/shared_libs/plays/runtime-validation.ts +0 -395
  79. package/dist/repo/shared_libs/temporal/constants.ts +0 -39
  80. package/dist/repo/shared_libs/temporal/preview-config.ts +0 -153
@@ -1,395 +0,0 @@
1
- import * as acorn from 'acorn';
2
- import { fullAncestor as walkFullAncestor } from 'acorn-walk';
3
- import type { PlayBundleArtifact } from './artifact-types';
4
- import type { PlayStructuredDefinition } from './definition';
5
- import { validatePlayStructuredDefinition } from './definition';
6
- import {
7
- MAP_KEY_NAMESPACE_MAX_LENGTH,
8
- normalizeTableNamespace,
9
- } from './row-identity';
10
- import { DISALLOWED_RUN_JAVASCRIPT_TOOL_MESSAGE } from '../play-runtime/runtime-constraints';
11
-
12
- export async function validatePlay(
13
- code: string | null | undefined,
14
- definition?: PlayStructuredDefinition | null,
15
- codeFormat: 'function' | 'cjs_module' | 'esm_module' = 'function',
16
- validationSource?: string | null,
17
- artifact?: PlayBundleArtifact | null,
18
- ): Promise<{ valid: boolean; errors: string[] }> {
19
- const errors: string[] = [];
20
-
21
- if (definition) {
22
- return validatePlayStructuredDefinition(definition);
23
- }
24
-
25
- const sourceForValidation = validationSource ?? code ?? '';
26
-
27
- if (!sourceForValidation.trim()) {
28
- return { valid: false, errors: ['Play code is required.'] };
29
- }
30
-
31
- try {
32
- if (codeFormat === 'cjs_module' && code?.trim()) {
33
- new Function('module', 'exports', 'require', code);
34
- } else if (codeFormat === 'esm_module' && code?.trim()) {
35
- // esm_module bundles target Cloudflare Workers; their top-level uses
36
- // import/export which `new Function` rejects. Skip the in-host parse
37
- // check — the bundler already typechecked + esbuild parsed the source.
38
- // The play Worker runtime catches any actual runtime errors.
39
- } else if (codeFormat !== 'cjs_module') {
40
- new Function('ctx', 'input', `return (${code})(ctx, input)`);
41
- }
42
- } catch (e) {
43
- errors.push(`Parse error: ${e instanceof Error ? e.message : String(e)}`);
44
- }
45
-
46
- errors.push(...validatePlayMapStructure(sourceForValidation));
47
- errors.push(...validateRuntimeSyntax(sourceForValidation));
48
-
49
- if (
50
- artifact &&
51
- artifact.codeFormat !== 'cjs_module' &&
52
- artifact.codeFormat !== 'esm_module'
53
- ) {
54
- errors.push(
55
- 'Play artifact codeFormat must be "cjs_module" or "esm_module".',
56
- );
57
- }
58
-
59
- return { valid: errors.length === 0, errors };
60
- }
61
-
62
- function validatePlayMapStructure(code: string): string[] {
63
- const errors: string[] = [];
64
- const calledPlayNames = new Set<string>();
65
- let ast: acorn.Node;
66
-
67
- try {
68
- ast = parsePlayAst(code);
69
- } catch {
70
- return errors;
71
- }
72
-
73
- walkFullAncestor(ast, (node, _state, ancestors) => {
74
- if (
75
- node.type === 'CallExpression' &&
76
- usesDisallowedRunJavascriptTool(node as acorn.CallExpression) &&
77
- hasMapResolverAncestor(ancestors)
78
- ) {
79
- errors.push(DISALLOWED_RUN_JAVASCRIPT_TOOL_MESSAGE);
80
- }
81
-
82
- if (!isCtxMapCall(node)) {
83
- const callExpression =
84
- (node as acorn.Node).type === 'CallExpression'
85
- ? (node as unknown as acorn.CallExpression)
86
- : null;
87
- if (
88
- callExpression &&
89
- callExpression.callee.type === 'MemberExpression' &&
90
- callExpression.callee.property.type === 'Identifier' &&
91
- callExpression.callee.property.name === 'runPlay'
92
- ) {
93
- const firstArgument = callExpression.arguments[0];
94
- if (
95
- firstArgument?.type === 'Literal' &&
96
- typeof firstArgument.value === 'string'
97
- ) {
98
- calledPlayNames.add(firstArgument.value);
99
- }
100
- }
101
- if (
102
- callExpression &&
103
- callExpression.callee.type === 'MemberExpression' &&
104
- callExpression.callee.property.type === 'Identifier' &&
105
- callExpression.callee.property.name === 'waterfall'
106
- ) {
107
- const firstArgument = callExpression.arguments[0];
108
- if (firstArgument?.type === 'ObjectExpression') {
109
- const minResultsProperty = firstArgument.properties.find(
110
- (prop) =>
111
- prop.type === 'Property' &&
112
- prop.key.type === 'Identifier' &&
113
- prop.key.name === 'minResults',
114
- );
115
- if (!minResultsProperty) {
116
- errors.push(
117
- 'Inline ctx.waterfall({...}) calls must declare minResults.',
118
- );
119
- }
120
- }
121
- }
122
- return;
123
- }
124
-
125
- if (hasMapResolverAncestor(ancestors)) {
126
- errors.push(
127
- 'Nested ctx.map() is not supported. Flatten work into a single map definition.',
128
- );
129
- return;
130
- }
131
-
132
- extractValidatedMapTableNamespace(node, errors);
133
- });
134
-
135
- const playNameMatch = code.match(
136
- /define(?:Play|Workflow)\s*\(\s*['"`]([^'"`]+)['"`]/,
137
- );
138
- const definedPlayName = playNameMatch?.[1]?.trim();
139
- if (definedPlayName && calledPlayNames.has(definedPlayName)) {
140
- errors.push(
141
- `Recursive play graph detected: ${definedPlayName} -> ${definedPlayName}. Use a different child play or refactor the shared logic.`,
142
- );
143
- }
144
-
145
- return [...new Set(errors)];
146
- }
147
-
148
- function validateRuntimeSyntax(code: string): string[] {
149
- const errors: string[] = [];
150
- let ast: acorn.Node;
151
-
152
- try {
153
- ast = parsePlayAst(code);
154
- } catch {
155
- return errors;
156
- }
157
-
158
- walkFullAncestor(ast, (node) => {
159
- if (node.type === 'ImportExpression') {
160
- errors.push(
161
- 'Dynamic import() is not allowed in plays. Use static imports instead.',
162
- );
163
- return;
164
- }
165
-
166
- if (node.type !== 'CallExpression') {
167
- return;
168
- }
169
-
170
- const callNode = node as acorn.CallExpression;
171
- if (
172
- callNode.callee.type !== 'Identifier' ||
173
- callNode.callee.name !== 'require'
174
- ) {
175
- return;
176
- }
177
-
178
- const firstArgument = callNode.arguments[0];
179
- const isLiteralString =
180
- firstArgument?.type === 'Literal' &&
181
- typeof firstArgument.value === 'string';
182
-
183
- if (!isLiteralString) {
184
- errors.push(
185
- 'Dynamic require() is not allowed in plays. Use require("literal") only.',
186
- );
187
- }
188
- });
189
-
190
- return [...new Set(errors)];
191
- }
192
-
193
- function parsePlayAst(code: string): acorn.Node {
194
- try {
195
- return acorn.parse(code, {
196
- ecmaVersion: 'latest',
197
- sourceType: 'module',
198
- allowAwaitOutsideFunction: true,
199
- }) as acorn.Node;
200
- } catch {
201
- return acorn.parse(`const __play = ${code};`, {
202
- ecmaVersion: 'latest',
203
- sourceType: 'module',
204
- }) as acorn.Node;
205
- }
206
- }
207
-
208
- function usesDisallowedRunJavascriptTool(node: acorn.CallExpression): boolean {
209
- const callee = node.callee;
210
- if (callee.type !== 'MemberExpression') {
211
- return false;
212
- }
213
-
214
- if (
215
- callee.property.type !== 'Identifier' ||
216
- callee.property.name !== 'tool'
217
- ) {
218
- return false;
219
- }
220
-
221
- const firstArgument = node.arguments[0];
222
- return (
223
- firstArgument?.type === 'Literal' &&
224
- firstArgument.value === 'run_javascript'
225
- );
226
- }
227
-
228
- function extractValidatedMapTableNamespace(
229
- node: acorn.CallExpression,
230
- errors: string[],
231
- ): string | null {
232
- const keyArgument = node.arguments[0];
233
- const rowsArgument = node.arguments[1];
234
- if (!keyArgument) {
235
- errors.push(
236
- 'ctx.map() requires a string literal map key as the first argument, e.g. ctx.map("leads", rows).step("company", row => row.domain).run({ key: "lead_id" }).',
237
- );
238
- return null;
239
- }
240
-
241
- if (!rowsArgument) {
242
- errors.push(
243
- 'ctx.map() requires rows as the second argument, e.g. ctx.map("leads", rows).step("company", row => row.domain).run({ key: "lead_id" }).',
244
- );
245
- return null;
246
- }
247
-
248
- if (keyArgument.type !== 'Literal' || typeof keyArgument.value !== 'string') {
249
- errors.push(
250
- 'ctx.map() requires a string literal key as the first argument so Deepline can precompute idempotency.',
251
- );
252
- return null;
253
- }
254
-
255
- if (!keyArgument.value.trim()) {
256
- errors.push(
257
- 'ctx.map() requires a non-empty string key as the first argument.',
258
- );
259
- return null;
260
- }
261
-
262
- try {
263
- normalizeTableNamespace(keyArgument.value);
264
- } catch (error) {
265
- errors.push(
266
- error instanceof Error
267
- ? `${error.message} Example: ctx.map("leads", rows).step("company", row => row.domain).run({ key: "lead_id", description: "..." }).`
268
- : `ctx.map() key must normalize to <= ${MAP_KEY_NAMESPACE_MAX_LENGTH} characters.`,
269
- );
270
- return null;
271
- }
272
-
273
- if (rowsArgument.type === 'ObjectExpression') {
274
- errors.push(
275
- 'ctx.map() key must not be an object. Use ctx.map("leads", rows).step(...).run({ key: "lead_id" }).',
276
- );
277
- return null;
278
- }
279
- if (
280
- rowsArgument.type === 'FunctionExpression' ||
281
- isFunctionNode(rowsArgument)
282
- ) {
283
- errors.push('ctx.map() requires rows as the second argument.');
284
- return null;
285
- }
286
-
287
- const optionsArgument = node.arguments[2];
288
- if (optionsArgument) {
289
- errors.push(
290
- 'ctx.map() accepts only a map key and rows. Add steps with .step(...) and pass row identity options to .run({ key: "lead_id" }).',
291
- );
292
- return null;
293
- }
294
-
295
- return keyArgument.value.trim();
296
- }
297
-
298
- function isCtxMapCall(node: acorn.Node): node is acorn.CallExpression {
299
- if (node.type !== 'CallExpression') {
300
- return false;
301
- }
302
- const callee = (node as acorn.CallExpression).callee;
303
- if (callee.type !== 'MemberExpression') {
304
- return false;
305
- }
306
- if (callee.property.type !== 'Identifier' || callee.property.name !== 'map') {
307
- return false;
308
- }
309
- if (callee.object.type !== 'Identifier') {
310
- return false;
311
- }
312
- return callee.object.name === 'ctx' || callee.object.name.endsWith('Ctx');
313
- }
314
-
315
- function isFunctionNode(
316
- node: acorn.Node | null | undefined,
317
- ): node is
318
- | acorn.FunctionDeclaration
319
- | acorn.FunctionExpression
320
- | acorn.ArrowFunctionExpression {
321
- return Boolean(
322
- node &&
323
- (node.type === 'FunctionDeclaration' ||
324
- node.type === 'FunctionExpression' ||
325
- node.type === 'ArrowFunctionExpression'),
326
- );
327
- }
328
-
329
- function hasMapResolverAncestor(ancestors: acorn.Node[]): boolean {
330
- for (let index = 0; index < ancestors.length; index += 1) {
331
- const node = ancestors[index];
332
- if (!isFunctionNode(node)) {
333
- continue;
334
- }
335
-
336
- const parent = index >= 1 ? ancestors[index - 1] : null;
337
- const grandparent = index >= 2 ? ancestors[index - 2] : null;
338
- const greatGrandparent = index >= 3 ? ancestors[index - 3] : null;
339
-
340
- if (
341
- parent?.type === 'CallExpression' &&
342
- isCtxMapCall(parent) &&
343
- parent.arguments[2] === node
344
- ) {
345
- return true;
346
- }
347
-
348
- if (
349
- parent?.type === 'CallExpression' &&
350
- isMapBuilderStepCall(parent) &&
351
- parent.arguments[1] === node
352
- ) {
353
- return true;
354
- }
355
-
356
- if (
357
- parent?.type === 'Property' &&
358
- (parent as acorn.Property).value === node &&
359
- grandparent?.type === 'ObjectExpression' &&
360
- greatGrandparent?.type === 'CallExpression' &&
361
- isCtxMapCall(greatGrandparent) &&
362
- greatGrandparent.arguments[2] === grandparent
363
- ) {
364
- return true;
365
- }
366
- }
367
-
368
- return false;
369
- }
370
-
371
- function isMapBuilderStepCall(node: acorn.Node): node is acorn.CallExpression {
372
- if (node.type !== 'CallExpression') return false;
373
- const callee = (node as acorn.CallExpression).callee;
374
- if (callee.type !== 'MemberExpression') return false;
375
- if (
376
- callee.property.type !== 'Identifier' ||
377
- callee.property.name !== 'step'
378
- ) {
379
- return false;
380
- }
381
- let current: acorn.Node = callee.object as acorn.Node;
382
- while (current.type === 'CallExpression') {
383
- if (isCtxMapCall(current)) return true;
384
- const nestedCallee = (current as acorn.CallExpression).callee;
385
- if (
386
- nestedCallee.type !== 'MemberExpression' ||
387
- nestedCallee.property.type !== 'Identifier' ||
388
- nestedCallee.property.name !== 'step'
389
- ) {
390
- return false;
391
- }
392
- current = nestedCallee.object as acorn.Node;
393
- }
394
- return false;
395
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * Shared Temporal execution constants.
3
- *
4
- * Keep values that both the API/auth surface and the worker need here so the
5
- * API never imports from worker-only modules.
6
- */
7
-
8
- /**
9
- * Local Temporal dev defaults.
10
- *
11
- * These match the host ports exposed by docker-compose.yml and the env files
12
- * used by the local dev flows (`.env.local`, `.env.worktree`).
13
- */
14
- export const LOCAL_TEMPORAL_FRONTEND_PORT = 17233;
15
- export const LOCAL_TEMPORAL_UI_PORT = 18233;
16
- export const LOCAL_TEMPORAL_NAMESPACE = 'default';
17
- export const LOCAL_TEMPORAL_ADDRESS =
18
- `127.0.0.1:${LOCAL_TEMPORAL_FRONTEND_PORT}`;
19
- export const LOCAL_TEMPORAL_UI_URL =
20
- `http://127.0.0.1:${LOCAL_TEMPORAL_UI_PORT}`;
21
-
22
- /** Maximum active user-code runtime for a standard play, in seconds. */
23
- export const STANDARD_PLAY_RUNTIME_LIMIT_SECONDS = 10 * 60; // 10 minutes
24
-
25
- /**
26
- * Activity timeout includes cleanup/billing headroom after the 10 minute
27
- * user-code runtime cap. Keep this higher than STANDARD_PLAY_RUNTIME_LIMIT_SECONDS.
28
- */
29
- export const PLAY_ACTIVITY_TIMEOUT_SECONDS = 12 * 60; // 12 minutes
30
-
31
- /** Heartbeat cadence for the long-running play execution activity. */
32
- export const PLAY_EXECUTE_ACTIVITY_HEARTBEAT_INTERVAL_SECONDS = 15;
33
-
34
- /**
35
- * TTL for workflow executor tokens, in seconds.
36
- * Matches the activity timeout so tokens expire when the activity would
37
- * time out anyway.
38
- */
39
- export const WORKFLOW_EXECUTOR_TOKEN_TTL_SECONDS = PLAY_ACTIVITY_TIMEOUT_SECONDS;
@@ -1,153 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import * as path from 'node:path';
3
- import * as dotenv from 'dotenv';
4
- import {
5
- LOCAL_TEMPORAL_ADDRESS,
6
- LOCAL_TEMPORAL_NAMESPACE,
7
- } from './constants';
8
-
9
- export const PLAY_TASK_QUEUE = 'deepline-plays';
10
- // Internal process flag set by `bun run dev:v2 --preview`. Do not put this in
11
- // .env.local; the dev command owns the mode selection so local/preview runs are
12
- // obvious at the call site.
13
- export const DEEPLINE_V2_INFRA_MODE_ENV = 'DEEPLINE_V2_INFRA_MODE';
14
- export const PREVIEW_PLAYS_ENV_FILE = '.env.plays.preview';
15
-
16
- type TemporalTlsConfig = {
17
- clientCertPair: {
18
- crt: Uint8Array;
19
- key: Uint8Array;
20
- };
21
- };
22
-
23
- export type DeeplineTemporalConfig = {
24
- address: string;
25
- namespace: string;
26
- taskQueue: string;
27
- tls?: TemporalTlsConfig;
28
- deployment: 'local' | 'preview';
29
- };
30
-
31
- let loadedPreviewEnv = false;
32
-
33
- function decodePemEnv(value: string): Uint8Array {
34
- return Buffer.from(value.replace(/\\n/g, '\n'), 'utf-8');
35
- }
36
-
37
- export function isPreviewPlaysDeployment(): boolean {
38
- const mode = process.env[DEEPLINE_V2_INFRA_MODE_ENV]?.trim().toLowerCase();
39
- return mode === 'external' || mode === 'preview';
40
- }
41
-
42
- export function isCloudflarePlaysDeployment(): boolean {
43
- const mode = process.env[DEEPLINE_V2_INFRA_MODE_ENV]?.trim().toLowerCase();
44
- return mode === 'cloudflare';
45
- }
46
-
47
- /**
48
- * True when the play runtime callback baseUrl must be a public URL — i.e. when
49
- * the plays runner runs outside the local app process and can't reach
50
- * 127.0.0.1. Both `external` (Daytona) and `cloudflare` (Workers/DOs) need
51
- * this; only fully-local mode can keep baseUrl on localhost.
52
- */
53
- export function requiresPublicCallbackBaseUrl(): boolean {
54
- return isPreviewPlaysDeployment() || isCloudflarePlaysDeployment();
55
- }
56
-
57
- export function loadPreviewPlaysEnv(cwd = process.cwd()): void {
58
- if (loadedPreviewEnv || !isPreviewPlaysDeployment()) {
59
- return;
60
- }
61
-
62
- const envPath = path.join(cwd, PREVIEW_PLAYS_ENV_FILE);
63
- if (existsSync(envPath)) {
64
- dotenv.config({ path: envPath, override: true });
65
- }
66
-
67
- loadedPreviewEnv = true;
68
- }
69
-
70
- function temporalTlsFromEnv(): TemporalTlsConfig | undefined {
71
- const cert =
72
- process.env.TEMPORAL_TLS_CERT_DATA ?? process.env.FAS_TEMPORAL_CERT_DATA;
73
- const key =
74
- process.env.TEMPORAL_TLS_KEY_DATA ?? process.env.FAS_TEMPORAL_KEY_DATA;
75
-
76
- if (!cert && !key) {
77
- return undefined;
78
- }
79
- if (!cert || !key) {
80
- throw new Error(
81
- 'Temporal Cloud mTLS requires both TEMPORAL_TLS_CERT_DATA and TEMPORAL_TLS_KEY_DATA.',
82
- );
83
- }
84
-
85
- return {
86
- clientCertPair: {
87
- crt: decodePemEnv(cert),
88
- key: decodePemEnv(key),
89
- },
90
- };
91
- }
92
-
93
- function temporalAddressFromEnv(): string | undefined {
94
- return (
95
- process.env.TEMPORAL_ADDRESS?.trim() ||
96
- process.env.FAS_TEMPORAL_ADDRESS?.trim() ||
97
- undefined
98
- );
99
- }
100
-
101
- function temporalNamespaceFromEnv(address: string): string | undefined {
102
- const previewConfigured = process.env.FAS_TEMPORAL_NAMESPACE?.trim();
103
- if (previewConfigured) {
104
- return previewConfigured;
105
- }
106
-
107
- const host = address.split(':')[0] ?? '';
108
- const temporalCloudNamespace = /^([^.]+\.[^.]+)\.tmprl\.cloud$/i.exec(host);
109
- if (temporalCloudNamespace?.[1]) {
110
- return temporalCloudNamespace[1];
111
- }
112
-
113
- const configured = process.env.TEMPORAL_NAMESPACE?.trim();
114
- return configured || undefined;
115
- }
116
-
117
- export function getDeeplineTemporalConfig(options?: {
118
- loadPreviewEnv?: boolean;
119
- }): DeeplineTemporalConfig {
120
- if (options?.loadPreviewEnv !== false) {
121
- loadPreviewPlaysEnv();
122
- }
123
-
124
- if (isPreviewPlaysDeployment()) {
125
- const address = temporalAddressFromEnv();
126
- const namespace = address ? temporalNamespaceFromEnv(address) : undefined;
127
- if (!address) {
128
- throw new Error(
129
- 'dev:v2 preview mode requires TEMPORAL_ADDRESS or FAS_TEMPORAL_ADDRESS.',
130
- );
131
- }
132
- if (!namespace) {
133
- throw new Error(
134
- 'dev:v2 preview mode requires TEMPORAL_NAMESPACE or FAS_TEMPORAL_NAMESPACE.',
135
- );
136
- }
137
- return {
138
- address,
139
- namespace,
140
- taskQueue: process.env.TEMPORAL_TASK_QUEUE?.trim() || PLAY_TASK_QUEUE,
141
- tls: temporalTlsFromEnv(),
142
- deployment: 'preview',
143
- };
144
- }
145
-
146
- return {
147
- address: process.env.TEMPORAL_ADDRESS ?? LOCAL_TEMPORAL_ADDRESS,
148
- namespace: process.env.TEMPORAL_NAMESPACE ?? LOCAL_TEMPORAL_NAMESPACE,
149
- taskQueue: process.env.TEMPORAL_TASK_QUEUE?.trim() || PLAY_TASK_QUEUE,
150
- tls: temporalTlsFromEnv(),
151
- deployment: 'local',
152
- };
153
- }