deepline 0.1.0 → 0.1.2
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.
- package/dist/cli/index.js +212 -54
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +198 -40
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3256 -0
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +710 -0
- package/dist/repo/apps/play-runner-workers/src/entry.ts +5070 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/README.md +21 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +177 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +52 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +100 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +184 -0
- package/dist/repo/sdk/src/cli/commands/auth.ts +482 -0
- package/dist/repo/sdk/src/cli/commands/billing.ts +188 -0
- package/dist/repo/sdk/src/cli/commands/csv.ts +123 -0
- package/dist/repo/sdk/src/cli/commands/db.ts +119 -0
- package/dist/repo/sdk/src/cli/commands/feedback.ts +40 -0
- package/dist/repo/sdk/src/cli/commands/org.ts +117 -0
- package/dist/repo/sdk/src/cli/commands/play.ts +3200 -0
- package/dist/repo/sdk/src/cli/commands/tools.ts +687 -0
- package/dist/repo/sdk/src/cli/dataset-stats.ts +341 -0
- package/dist/repo/sdk/src/cli/index.ts +138 -0
- package/dist/repo/sdk/src/cli/progress.ts +135 -0
- package/dist/repo/sdk/src/cli/trace.ts +61 -0
- package/dist/repo/sdk/src/cli/utils.ts +145 -0
- package/dist/repo/sdk/src/client.ts +1188 -0
- package/dist/repo/sdk/src/compat.ts +77 -0
- package/dist/repo/sdk/src/config.ts +285 -0
- package/dist/repo/sdk/src/errors.ts +125 -0
- package/dist/repo/sdk/src/http.ts +391 -0
- package/dist/repo/sdk/src/index.ts +139 -0
- package/dist/repo/sdk/src/play.ts +1330 -0
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +133 -0
- package/dist/repo/sdk/src/plays/harness-stub.ts +210 -0
- package/dist/repo/sdk/src/plays/local-file-discovery.ts +326 -0
- package/dist/repo/sdk/src/tool-output.ts +489 -0
- package/dist/repo/sdk/src/types.ts +669 -0
- package/dist/repo/sdk/src/version.ts +2 -0
- package/dist/repo/sdk/src/worker-play-entry.ts +286 -0
- package/dist/repo/shared_libs/observability/node-tracing.ts +129 -0
- package/dist/repo/shared_libs/observability/tracing.ts +98 -0
- package/dist/repo/shared_libs/play-runtime/backend.ts +139 -0
- package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +182 -0
- package/dist/repo/shared_libs/play-runtime/batching-types.ts +91 -0
- package/dist/repo/shared_libs/play-runtime/context.ts +3999 -0
- package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +78 -0
- package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +250 -0
- package/dist/repo/shared_libs/play-runtime/ctx-types.ts +713 -0
- package/dist/repo/shared_libs/play-runtime/dataset-id.ts +10 -0
- package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +304 -0
- package/dist/repo/shared_libs/play-runtime/db-session.ts +462 -0
- package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
- package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +124 -0
- package/dist/repo/shared_libs/play-runtime/execution-plan.ts +262 -0
- package/dist/repo/shared_libs/play-runtime/live-events.ts +214 -0
- package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +50 -0
- package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +114 -0
- package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +158 -0
- package/dist/repo/shared_libs/play-runtime/profiles.ts +90 -0
- package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +172 -0
- package/dist/repo/shared_libs/play-runtime/protocol.ts +121 -0
- package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +42 -0
- package/dist/repo/shared_libs/play-runtime/result-normalization.ts +33 -0
- package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +208 -0
- package/dist/repo/shared_libs/play-runtime/runtime-api.ts +1873 -0
- package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +2 -0
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +201 -0
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +48 -0
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +84 -0
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +174 -0
- package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +147 -0
- package/dist/repo/shared_libs/play-runtime/suspension.ts +68 -0
- package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +146 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +387 -0
- package/dist/repo/shared_libs/play-runtime/tracing.ts +31 -0
- package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +75 -0
- package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +140 -0
- package/dist/repo/shared_libs/plays/artifact-transport.ts +14 -0
- package/dist/repo/shared_libs/plays/artifact-types.ts +49 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +1346 -0
- package/dist/repo/shared_libs/plays/compiler-manifest.ts +186 -0
- package/dist/repo/shared_libs/plays/contracts.ts +51 -0
- package/dist/repo/shared_libs/plays/dataset.ts +308 -0
- package/dist/repo/shared_libs/plays/definition.ts +264 -0
- package/dist/repo/shared_libs/plays/file-refs.ts +11 -0
- package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +206 -0
- package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +164 -0
- package/dist/repo/shared_libs/plays/row-identity.ts +302 -0
- package/dist/repo/shared_libs/plays/runtime-validation.ts +415 -0
- package/dist/repo/shared_libs/plays/static-pipeline.ts +560 -0
- package/dist/repo/shared_libs/temporal/constants.ts +39 -0
- package/dist/repo/shared_libs/temporal/preview-config.ts +153 -0
- package/package.json +4 -4
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { PlayArtifactKind } from '../play-runtime/backend';
|
|
2
|
+
|
|
3
|
+
export interface PlayStaticPipelineSnapshot {
|
|
4
|
+
tableNamespace?: string;
|
|
5
|
+
inputFields?: string[];
|
|
6
|
+
csvArg?: string;
|
|
7
|
+
hasInlineData?: boolean;
|
|
8
|
+
csvDescription?: string;
|
|
9
|
+
mapDescription?: string;
|
|
10
|
+
fields: string[];
|
|
11
|
+
stages?: PlayStaticSubstepSnapshot[];
|
|
12
|
+
substeps: PlayStaticSubstepSnapshot[];
|
|
13
|
+
sheetContract?: PlaySheetContractSnapshot | null;
|
|
14
|
+
sheetContractErrors?: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type PlaySheetColumnSourceSnapshot =
|
|
18
|
+
| 'input'
|
|
19
|
+
| 'mapField'
|
|
20
|
+
| 'waterfallStep'
|
|
21
|
+
| 'childPlayColumn';
|
|
22
|
+
|
|
23
|
+
export interface PlaySheetColumnContractSnapshot {
|
|
24
|
+
id: string;
|
|
25
|
+
sqlName: string;
|
|
26
|
+
source: PlaySheetColumnSourceSnapshot;
|
|
27
|
+
field?: string;
|
|
28
|
+
parentField?: string;
|
|
29
|
+
playId?: string;
|
|
30
|
+
waterfallId?: string;
|
|
31
|
+
outputField?: string;
|
|
32
|
+
outputSqlName?: string;
|
|
33
|
+
stepId?: string;
|
|
34
|
+
toolId?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface PlaySheetContractSnapshot {
|
|
38
|
+
tableNamespace: string;
|
|
39
|
+
columns: PlaySheetColumnContractSnapshot[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface PlayStaticSourceRangeSnapshot {
|
|
43
|
+
sourcePath?: string;
|
|
44
|
+
startLine: number;
|
|
45
|
+
endLine: number;
|
|
46
|
+
startColumn: number;
|
|
47
|
+
endColumn: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type PlayStaticSubstepMetadataSnapshot = {
|
|
51
|
+
conditional?: boolean;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type PlayStaticSubstepSnapshot = PlayStaticSubstepMetadataSnapshot &
|
|
55
|
+
(
|
|
56
|
+
| {
|
|
57
|
+
type: 'csv';
|
|
58
|
+
field: string;
|
|
59
|
+
path?: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
62
|
+
callDepth?: number;
|
|
63
|
+
callPath?: string[];
|
|
64
|
+
}
|
|
65
|
+
| {
|
|
66
|
+
type: 'map';
|
|
67
|
+
field: string;
|
|
68
|
+
name?: string;
|
|
69
|
+
tableNamespace?: string;
|
|
70
|
+
inputFields?: string[];
|
|
71
|
+
outputFields?: string[];
|
|
72
|
+
waterfallIds?: string[];
|
|
73
|
+
sheetContract?: PlaySheetContractSnapshot | null;
|
|
74
|
+
description?: string;
|
|
75
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
76
|
+
callDepth?: number;
|
|
77
|
+
callPath?: string[];
|
|
78
|
+
}
|
|
79
|
+
| {
|
|
80
|
+
type: 'tool';
|
|
81
|
+
toolId: string;
|
|
82
|
+
field: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
inLoop?: boolean;
|
|
85
|
+
isEventWait?: boolean;
|
|
86
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
87
|
+
callDepth?: number;
|
|
88
|
+
callPath?: string[];
|
|
89
|
+
}
|
|
90
|
+
| {
|
|
91
|
+
type: 'waterfall';
|
|
92
|
+
tool?: string;
|
|
93
|
+
field: string;
|
|
94
|
+
inLoop?: boolean;
|
|
95
|
+
id?: string;
|
|
96
|
+
output?: string;
|
|
97
|
+
minResults?: number;
|
|
98
|
+
sourceText?: string;
|
|
99
|
+
steps?: Array<{
|
|
100
|
+
id: string;
|
|
101
|
+
kind?: 'tool' | 'code';
|
|
102
|
+
toolId?: string;
|
|
103
|
+
paramsSource?: string;
|
|
104
|
+
}>;
|
|
105
|
+
description?: string;
|
|
106
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
107
|
+
callDepth?: number;
|
|
108
|
+
callPath?: string[];
|
|
109
|
+
}
|
|
110
|
+
| {
|
|
111
|
+
type: 'step_suite';
|
|
112
|
+
field: string;
|
|
113
|
+
steps: PlayStaticSubstepSnapshot[];
|
|
114
|
+
returnSource?: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
117
|
+
callDepth?: number;
|
|
118
|
+
callPath?: string[];
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
type: 'play_call';
|
|
122
|
+
playId: string;
|
|
123
|
+
field: string;
|
|
124
|
+
inLoop?: boolean;
|
|
125
|
+
pipeline?: PlayStaticPipelineSnapshot | null;
|
|
126
|
+
cycleDetected?: boolean;
|
|
127
|
+
resolutionError?: string;
|
|
128
|
+
description?: string;
|
|
129
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
130
|
+
callDepth?: number;
|
|
131
|
+
callPath?: string[];
|
|
132
|
+
}
|
|
133
|
+
| {
|
|
134
|
+
type: 'run_javascript';
|
|
135
|
+
alias: string;
|
|
136
|
+
description?: string;
|
|
137
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
138
|
+
callDepth?: number;
|
|
139
|
+
callPath?: string[];
|
|
140
|
+
}
|
|
141
|
+
| {
|
|
142
|
+
type: 'code';
|
|
143
|
+
field: string;
|
|
144
|
+
description?: string;
|
|
145
|
+
sourceRange?: PlayStaticSourceRangeSnapshot;
|
|
146
|
+
callDepth?: number;
|
|
147
|
+
callPath?: string[];
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
export const PLAY_COMPILER_MANIFEST_VERSION = 1;
|
|
152
|
+
|
|
153
|
+
export type PlayCompilerDependencyManifest = {
|
|
154
|
+
playName: string;
|
|
155
|
+
sourceHash: string;
|
|
156
|
+
graphHash: string;
|
|
157
|
+
artifactHash: string;
|
|
158
|
+
staticPipeline: PlayStaticPipelineSnapshot;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export type PlayCompilerManifest = {
|
|
162
|
+
compilerVersion: number;
|
|
163
|
+
playName: string;
|
|
164
|
+
sourceHash: string;
|
|
165
|
+
graphHash: string;
|
|
166
|
+
artifactHash: string;
|
|
167
|
+
artifactKind?: PlayArtifactKind;
|
|
168
|
+
staticPipeline: PlayStaticPipelineSnapshot;
|
|
169
|
+
importedPlayDependencies: PlayCompilerDependencyManifest[];
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export type PlayRuntimeManifest = {
|
|
173
|
+
playName?: string;
|
|
174
|
+
graphHash: string;
|
|
175
|
+
artifactHash: string;
|
|
176
|
+
artifactStorageKey: string;
|
|
177
|
+
staticPipelineHash: string;
|
|
178
|
+
staticPipeline: PlayStaticPipelineSnapshot;
|
|
179
|
+
compiledAt: number;
|
|
180
|
+
compilerVersion: string;
|
|
181
|
+
sourceCode?: string | null;
|
|
182
|
+
dynamicWorkerCode?: string | null;
|
|
183
|
+
maxCreditsPerRun?: number | null;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export type PlayRuntimeManifestMap = Record<string, PlayRuntimeManifest>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type PlayContractSource = 'ad_hoc' | 'draft' | 'published';
|
|
2
|
+
|
|
3
|
+
export type PlayRuntimeFeature =
|
|
4
|
+
| 'artifact_storage'
|
|
5
|
+
| 'checkpoint_resume'
|
|
6
|
+
| 'durable_sleep'
|
|
7
|
+
| 'packaged_files';
|
|
8
|
+
|
|
9
|
+
export const PLAY_PUBLIC_API_VERSION = 1;
|
|
10
|
+
export const PLAY_ARTIFACT_VERSION = 1;
|
|
11
|
+
export const PLAY_MIN_RUNNER_VERSION = 1;
|
|
12
|
+
export const PLAY_RUNTIME_FEATURES: PlayRuntimeFeature[] = [
|
|
13
|
+
'artifact_storage',
|
|
14
|
+
'checkpoint_resume',
|
|
15
|
+
'durable_sleep',
|
|
16
|
+
'packaged_files',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export type PlayContractCompatibilitySnapshot = {
|
|
20
|
+
apiVersion: number;
|
|
21
|
+
artifactVersion: number;
|
|
22
|
+
minRunnerVersion: number;
|
|
23
|
+
runtimeFeatures: PlayRuntimeFeature[];
|
|
24
|
+
runtimeBackend?: string | null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function buildPlayContractCompatibility(input?: {
|
|
28
|
+
runtimeBackend?: string | null;
|
|
29
|
+
}): PlayContractCompatibilitySnapshot {
|
|
30
|
+
return {
|
|
31
|
+
apiVersion: PLAY_PUBLIC_API_VERSION,
|
|
32
|
+
artifactVersion: PLAY_ARTIFACT_VERSION,
|
|
33
|
+
minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
|
|
34
|
+
runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
|
|
35
|
+
runtimeBackend: input?.runtimeBackend ?? null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type PlayRunContractSnapshot = {
|
|
40
|
+
source: PlayContractSource;
|
|
41
|
+
revisionVersion?: number | null;
|
|
42
|
+
staticPipeline?: unknown;
|
|
43
|
+
billingLimit?: {
|
|
44
|
+
maxCreditsPerRun?: number | null;
|
|
45
|
+
} | null;
|
|
46
|
+
structuredDefinition?: unknown;
|
|
47
|
+
artifactMetadata?: Record<string, unknown> | null;
|
|
48
|
+
codeFormat?: 'function' | 'cjs_module' | 'esm_module' | null;
|
|
49
|
+
sourceCode?: string | null;
|
|
50
|
+
compatibility?: PlayContractCompatibilitySnapshot | null;
|
|
51
|
+
};
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import type { PlayExecutionFileRef } from './file-refs';
|
|
2
|
+
|
|
3
|
+
const PLAY_DATASET_BRAND = Symbol.for('deepline.play.dataset');
|
|
4
|
+
const NODE_INSPECT_CUSTOM = Symbol.for('nodejs.util.inspect.custom');
|
|
5
|
+
const DEFAULT_MATERIALIZE_LIMIT = 10_000;
|
|
6
|
+
|
|
7
|
+
export type PlayDatasetKind = 'csv' | 'map';
|
|
8
|
+
|
|
9
|
+
export type PlayDatasetBacking =
|
|
10
|
+
| {
|
|
11
|
+
storage: 'neon_sheet';
|
|
12
|
+
sheet: {
|
|
13
|
+
playName: string;
|
|
14
|
+
tableNamespace: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
storage: 'r2_file';
|
|
19
|
+
file: PlayExecutionFileRef;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface SerializedPlayDataset<T> {
|
|
23
|
+
kind: 'dataset';
|
|
24
|
+
datasetKind: PlayDatasetKind;
|
|
25
|
+
datasetId: string;
|
|
26
|
+
count: number;
|
|
27
|
+
backing?: PlayDatasetBacking;
|
|
28
|
+
sourceLabel?: string | null;
|
|
29
|
+
tableNamespace?: string | null;
|
|
30
|
+
columns?: string[];
|
|
31
|
+
preview: T[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type PlayDatasetInput<T> =
|
|
35
|
+
| ReadonlyArray<T>
|
|
36
|
+
| Iterable<T>
|
|
37
|
+
| AsyncIterable<T>
|
|
38
|
+
| PlayDataset<T>;
|
|
39
|
+
|
|
40
|
+
export interface PlayDataset<T> extends AsyncIterable<T> {
|
|
41
|
+
readonly [PLAY_DATASET_BRAND]: true;
|
|
42
|
+
readonly datasetKind: PlayDatasetKind;
|
|
43
|
+
readonly datasetId: string;
|
|
44
|
+
readonly backing?: PlayDatasetBacking;
|
|
45
|
+
readonly sourceLabel?: string | null;
|
|
46
|
+
readonly tableNamespace?: string | null;
|
|
47
|
+
count(): Promise<number>;
|
|
48
|
+
peek(limit?: number): Promise<T[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Explicit escape hatch for bounded result sets.
|
|
51
|
+
* Large datasets should flow by handle through Neon-backed storage, not
|
|
52
|
+
* through worker memory as giant arrays.
|
|
53
|
+
*/
|
|
54
|
+
materialize(limit?: number): Promise<T[]>;
|
|
55
|
+
toJSON(): {
|
|
56
|
+
kind: 'dataset';
|
|
57
|
+
datasetKind: PlayDatasetKind;
|
|
58
|
+
datasetId: string;
|
|
59
|
+
count: number;
|
|
60
|
+
backing?: PlayDatasetBacking;
|
|
61
|
+
sourceLabel?: string | null;
|
|
62
|
+
tableNamespace?: string | null;
|
|
63
|
+
columns?: string[];
|
|
64
|
+
preview: T[];
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type PlayDatasetResolvers<T> = {
|
|
69
|
+
count: () => Promise<number>;
|
|
70
|
+
peek: (limit: number) => Promise<T[]>;
|
|
71
|
+
materialize: (limit?: number) => Promise<T[]>;
|
|
72
|
+
iterate: () => AsyncIterable<T>;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
function resolveMaterializeLimitCap(): number {
|
|
76
|
+
const raw = process.env.DEEPLINE_PLAY_DATASET_MATERIALIZE_LIMIT;
|
|
77
|
+
const parsed = raw ? Number(raw) : NaN;
|
|
78
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
79
|
+
return Math.floor(parsed);
|
|
80
|
+
}
|
|
81
|
+
return DEFAULT_MATERIALIZE_LIMIT;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function inferPreviewColumns<T>(rows: readonly T[]): string[] | undefined {
|
|
85
|
+
const columns = new Set<string>();
|
|
86
|
+
for (const row of rows) {
|
|
87
|
+
if (!row || typeof row !== 'object' || Array.isArray(row)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
for (const key of Object.keys(row as Record<string, unknown>)) {
|
|
91
|
+
columns.add(key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return columns.size > 0 ? [...columns] : undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function isPlayDataset<T>(value: unknown): value is PlayDataset<T> {
|
|
98
|
+
return Boolean(
|
|
99
|
+
value &&
|
|
100
|
+
typeof value === 'object' &&
|
|
101
|
+
(value as Record<PropertyKey, unknown>)[PLAY_DATASET_BRAND] === true,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function isSerializedPlayDataset<T>(
|
|
106
|
+
value: unknown,
|
|
107
|
+
): value is SerializedPlayDataset<T> {
|
|
108
|
+
return Boolean(
|
|
109
|
+
value &&
|
|
110
|
+
typeof value === 'object' &&
|
|
111
|
+
!Array.isArray(value) &&
|
|
112
|
+
(value as Record<string, unknown>).kind === 'dataset' &&
|
|
113
|
+
typeof (value as Record<string, unknown>).datasetKind === 'string' &&
|
|
114
|
+
typeof (value as Record<string, unknown>).datasetId === 'string' &&
|
|
115
|
+
typeof (value as Record<string, unknown>).count === 'number' &&
|
|
116
|
+
Array.isArray((value as Record<string, unknown>).preview),
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function trimSerializedPlayDatasetPreview<T>(
|
|
121
|
+
dataset: SerializedPlayDataset<T>,
|
|
122
|
+
limit: number,
|
|
123
|
+
): SerializedPlayDataset<T> {
|
|
124
|
+
return {
|
|
125
|
+
...dataset,
|
|
126
|
+
preview: dataset.preview.slice(0, Math.max(0, limit)),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
131
|
+
readonly [PLAY_DATASET_BRAND] = true as const;
|
|
132
|
+
readonly datasetKind: PlayDatasetKind;
|
|
133
|
+
readonly datasetId: string;
|
|
134
|
+
readonly backing?: PlayDatasetBacking;
|
|
135
|
+
readonly sourceLabel?: string | null;
|
|
136
|
+
readonly tableNamespace?: string | null;
|
|
137
|
+
private readonly previewRows: readonly T[];
|
|
138
|
+
private readonly previewColumns?: string[];
|
|
139
|
+
private cachedCount: number;
|
|
140
|
+
private readonly resolvers: PlayDatasetResolvers<T>;
|
|
141
|
+
|
|
142
|
+
constructor(input: {
|
|
143
|
+
datasetKind: PlayDatasetKind;
|
|
144
|
+
datasetId: string;
|
|
145
|
+
count: number;
|
|
146
|
+
backing?: PlayDatasetBacking;
|
|
147
|
+
previewRows: readonly T[];
|
|
148
|
+
sourceLabel?: string | null;
|
|
149
|
+
tableNamespace?: string | null;
|
|
150
|
+
resolvers: PlayDatasetResolvers<T>;
|
|
151
|
+
}) {
|
|
152
|
+
this.datasetKind = input.datasetKind;
|
|
153
|
+
this.datasetId = input.datasetId;
|
|
154
|
+
this.cachedCount = input.count;
|
|
155
|
+
this.backing = input.backing;
|
|
156
|
+
this.previewRows = input.previewRows;
|
|
157
|
+
this.previewColumns = inferPreviewColumns(this.previewRows);
|
|
158
|
+
this.sourceLabel = input.sourceLabel ?? null;
|
|
159
|
+
this.tableNamespace = input.tableNamespace ?? null;
|
|
160
|
+
this.resolvers = input.resolvers;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async count(): Promise<number> {
|
|
164
|
+
this.cachedCount = await this.resolvers.count();
|
|
165
|
+
return this.cachedCount;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async peek(limit = 10): Promise<T[]> {
|
|
169
|
+
if (limit <= this.previewRows.length) {
|
|
170
|
+
return this.previewRows.slice(0, Math.max(0, limit));
|
|
171
|
+
}
|
|
172
|
+
return await this.resolvers.peek(limit);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async materialize(limit?: number): Promise<T[]> {
|
|
176
|
+
const requestedLimit =
|
|
177
|
+
limit !== undefined ? Math.max(0, Math.floor(limit)) : undefined;
|
|
178
|
+
const cap = resolveMaterializeLimitCap();
|
|
179
|
+
if (requestedLimit !== undefined) {
|
|
180
|
+
if (requestedLimit > cap) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`PlayDataset.materialize(${requestedLimit}) exceeds the hard limit of ${cap} rows. ` +
|
|
183
|
+
'Return the dataset handle instead, or request a smaller bounded slice.',
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
return await this.resolvers.materialize(requestedLimit);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const count = await this.count();
|
|
190
|
+
if (count > cap) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`PlayDataset.materialize() refuses to load ${count} rows into memory. ` +
|
|
193
|
+
`The hard limit is ${cap}. Return the dataset handle instead or call materialize(limit).`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return await this.resolvers.materialize();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async *[Symbol.asyncIterator](): AsyncIterator<T> {
|
|
200
|
+
for await (const row of this.resolvers.iterate()) {
|
|
201
|
+
yield row;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
toJSON() {
|
|
206
|
+
return {
|
|
207
|
+
kind: 'dataset' as const,
|
|
208
|
+
datasetKind: this.datasetKind,
|
|
209
|
+
datasetId: this.datasetId,
|
|
210
|
+
count: this.cachedCount,
|
|
211
|
+
...(this.backing ? { backing: this.backing } : {}),
|
|
212
|
+
...(this.sourceLabel ? { sourceLabel: this.sourceLabel } : {}),
|
|
213
|
+
...(this.tableNamespace ? { tableNamespace: this.tableNamespace } : {}),
|
|
214
|
+
...(this.previewColumns ? { columns: this.previewColumns } : {}),
|
|
215
|
+
preview: [...this.previewRows],
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
[NODE_INSPECT_CUSTOM]() {
|
|
220
|
+
return this.toJSON();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function createDeferredPlayDataset<T>(input: {
|
|
225
|
+
datasetKind: PlayDatasetKind;
|
|
226
|
+
datasetId: string;
|
|
227
|
+
count: number;
|
|
228
|
+
backing?: PlayDatasetBacking;
|
|
229
|
+
previewRows?: readonly T[];
|
|
230
|
+
sourceLabel?: string | null;
|
|
231
|
+
tableNamespace?: string | null;
|
|
232
|
+
resolvers: PlayDatasetResolvers<T>;
|
|
233
|
+
}): PlayDataset<T> {
|
|
234
|
+
return new DeferredPlayDataset({
|
|
235
|
+
...input,
|
|
236
|
+
previewRows: input.previewRows ?? [],
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function createPlayDataset<T>(
|
|
241
|
+
rows: readonly T[],
|
|
242
|
+
metadata?: {
|
|
243
|
+
kind?: PlayDatasetKind;
|
|
244
|
+
sourceLabel?: string | null;
|
|
245
|
+
tableNamespace?: string | null;
|
|
246
|
+
datasetId?: string;
|
|
247
|
+
},
|
|
248
|
+
): PlayDataset<T> {
|
|
249
|
+
// Test/dev helper only. Production play execution should construct
|
|
250
|
+
// Neon-backed handles via createDeferredPlayDataset + runtime-host helpers.
|
|
251
|
+
const materializedRows = [...rows];
|
|
252
|
+
return createDeferredPlayDataset({
|
|
253
|
+
datasetKind: metadata?.kind ?? 'map',
|
|
254
|
+
datasetId:
|
|
255
|
+
metadata?.datasetId ??
|
|
256
|
+
`${metadata?.kind ?? 'map'}:${metadata?.tableNamespace ?? metadata?.sourceLabel ?? 'inline'}`,
|
|
257
|
+
count: materializedRows.length,
|
|
258
|
+
previewRows: materializedRows.slice(0, 10),
|
|
259
|
+
sourceLabel: metadata?.sourceLabel ?? null,
|
|
260
|
+
tableNamespace: metadata?.tableNamespace ?? null,
|
|
261
|
+
resolvers: {
|
|
262
|
+
count: async () => materializedRows.length,
|
|
263
|
+
peek: async (limit) =>
|
|
264
|
+
materializedRows.slice(0, Math.max(0, limit)),
|
|
265
|
+
materialize: async (limit) =>
|
|
266
|
+
limit === undefined
|
|
267
|
+
? [...materializedRows]
|
|
268
|
+
: materializedRows.slice(0, Math.max(0, limit)),
|
|
269
|
+
iterate: () =>
|
|
270
|
+
({
|
|
271
|
+
async *[Symbol.asyncIterator]() {
|
|
272
|
+
for (const row of materializedRows) {
|
|
273
|
+
yield row;
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
}) as AsyncIterable<T>,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export async function materializePlayDatasetInput<T>(
|
|
282
|
+
input: PlayDatasetInput<T>,
|
|
283
|
+
): Promise<T[]> {
|
|
284
|
+
if (isPlayDataset(input)) {
|
|
285
|
+
return await input.materialize();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (Array.isArray(input)) {
|
|
289
|
+
return [...input];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const rows: T[] = [];
|
|
293
|
+
if (
|
|
294
|
+
input != null &&
|
|
295
|
+
typeof input === 'object' &&
|
|
296
|
+
Symbol.asyncIterator in input
|
|
297
|
+
) {
|
|
298
|
+
for await (const row of input as AsyncIterable<T>) {
|
|
299
|
+
rows.push(row);
|
|
300
|
+
}
|
|
301
|
+
return rows;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
for (const row of input as Iterable<T>) {
|
|
305
|
+
rows.push(row);
|
|
306
|
+
}
|
|
307
|
+
return rows;
|
|
308
|
+
}
|