deepline 0.1.103 → 0.1.105
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 +577 -16
- package/dist/cli/index.mjs +577 -16
- package/dist/index.d.mts +184 -1
- package/dist/index.d.ts +184 -1
- package/dist/index.js +135 -9
- package/dist/index.mjs +135 -9
- package/dist/repo/sdk/src/client.ts +312 -6
- package/dist/repo/sdk/src/http.ts +12 -1
- package/dist/repo/sdk/src/index.ts +6 -0
- package/dist/repo/sdk/src/release.ts +5 -2
- package/dist/repo/shared_libs/play-runtime/csv-rename.ts +26 -0
- package/dist/repo/shared_libs/play-runtime/providers.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +2 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -188,10 +188,13 @@ var SDK_RELEASE = {
|
|
|
188
188
|
// preflight (existence, data rows, quotes, duplicate headers), HTML error
|
|
189
189
|
// scrubbing, and word-boundary watch truncation.
|
|
190
190
|
// 0.1.103 ships the refined SDK CLI command surface.
|
|
191
|
-
|
|
191
|
+
// 0.1.104 ships postgres_fast suspension/billing parity and runtime worker hardening.
|
|
192
|
+
// 0.1.105 ships the billing catalog surface: billing plans, subscribe,
|
|
193
|
+
// subscription status/cancel, invoices, and the client.billing namespace.
|
|
194
|
+
version: "0.1.105",
|
|
192
195
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
193
196
|
supportPolicy: {
|
|
194
|
-
latest: "0.1.
|
|
197
|
+
latest: "0.1.105",
|
|
195
198
|
minimumSupported: "0.1.53",
|
|
196
199
|
deprecatedBelow: "0.1.53"
|
|
197
200
|
}
|
|
@@ -322,7 +325,7 @@ var HttpClient = class {
|
|
|
322
325
|
signal: controller.signal
|
|
323
326
|
});
|
|
324
327
|
clearTimeout(timeoutId);
|
|
325
|
-
if (response.status === 401 || response.status === 403) {
|
|
328
|
+
if (response.status === 401 || response.status === 403 && !options?.forbiddenAsApiError) {
|
|
326
329
|
throw new AuthError();
|
|
327
330
|
}
|
|
328
331
|
if (response.status === 429) {
|
|
@@ -1414,6 +1417,9 @@ var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
|
1414
1417
|
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
1415
1418
|
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
|
|
1416
1419
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
1420
|
+
var REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
|
|
1421
|
+
var REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT = 3;
|
|
1422
|
+
var REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES = 25e5;
|
|
1417
1423
|
function sleep2(ms) {
|
|
1418
1424
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1419
1425
|
}
|
|
@@ -1426,6 +1432,45 @@ function isTransientCompileManifestError(error) {
|
|
|
1426
1432
|
message
|
|
1427
1433
|
);
|
|
1428
1434
|
}
|
|
1435
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
1436
|
+
const results = new Array(items.length);
|
|
1437
|
+
let nextIndex = 0;
|
|
1438
|
+
const workerCount = Math.min(Math.max(1, concurrency), items.length);
|
|
1439
|
+
await Promise.all(
|
|
1440
|
+
Array.from({ length: workerCount }, async () => {
|
|
1441
|
+
for (; ; ) {
|
|
1442
|
+
const index = nextIndex;
|
|
1443
|
+
nextIndex += 1;
|
|
1444
|
+
if (index >= items.length) {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
results[index] = await mapper(items[index], index);
|
|
1448
|
+
}
|
|
1449
|
+
})
|
|
1450
|
+
);
|
|
1451
|
+
return results;
|
|
1452
|
+
}
|
|
1453
|
+
function jsonUtf8Bytes(value) {
|
|
1454
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
1455
|
+
}
|
|
1456
|
+
function chunkRegisterPlayArtifacts(artifacts) {
|
|
1457
|
+
const chunks = [];
|
|
1458
|
+
let current = [];
|
|
1459
|
+
for (const artifact of artifacts) {
|
|
1460
|
+
const candidate = [...current, artifact];
|
|
1461
|
+
const candidateTooLarge = candidate.length > REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT || jsonUtf8Bytes({ artifacts: candidate }) > REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES;
|
|
1462
|
+
if (current.length > 0 && candidateTooLarge) {
|
|
1463
|
+
chunks.push(current);
|
|
1464
|
+
current = [artifact];
|
|
1465
|
+
} else {
|
|
1466
|
+
current = candidate;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
if (current.length > 0) {
|
|
1470
|
+
chunks.push(current);
|
|
1471
|
+
}
|
|
1472
|
+
return chunks;
|
|
1473
|
+
}
|
|
1429
1474
|
var RUN_LOGS_PAGE_LIMIT = 1e3;
|
|
1430
1475
|
function isRecord2(value) {
|
|
1431
1476
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -1593,6 +1638,8 @@ var DeeplineClient = class {
|
|
|
1593
1638
|
config;
|
|
1594
1639
|
/** Canonical run lifecycle namespace backed by `/api/v2/runs`. */
|
|
1595
1640
|
runs;
|
|
1641
|
+
/** Billing namespace: subscription status/cancel and invoice history. */
|
|
1642
|
+
billing;
|
|
1596
1643
|
/**
|
|
1597
1644
|
* Create a low-level SDK client.
|
|
1598
1645
|
*
|
|
@@ -1613,6 +1660,16 @@ var DeeplineClient = class {
|
|
|
1613
1660
|
exportDatasetRows: (input) => this.getPlaySheetRows(input),
|
|
1614
1661
|
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
1615
1662
|
};
|
|
1663
|
+
this.billing = {
|
|
1664
|
+
plans: () => this.getBillingPlans(),
|
|
1665
|
+
subscription: {
|
|
1666
|
+
status: () => this.getBillingSubscriptionStatus(),
|
|
1667
|
+
cancel: (options2) => this.cancelBillingSubscription(options2)
|
|
1668
|
+
},
|
|
1669
|
+
invoices: {
|
|
1670
|
+
list: (options2) => this.listBillingInvoices(options2)
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1616
1673
|
}
|
|
1617
1674
|
/** The resolved base URL this client is targeting (e.g. `"http://localhost:3000"`). */
|
|
1618
1675
|
get baseUrl() {
|
|
@@ -1981,8 +2038,13 @@ var DeeplineClient = class {
|
|
|
1981
2038
|
* first when a compiler manifest is not already supplied.
|
|
1982
2039
|
*/
|
|
1983
2040
|
async registerPlayArtifacts(artifacts) {
|
|
1984
|
-
|
|
1985
|
-
|
|
2041
|
+
if (artifacts.length === 0) {
|
|
2042
|
+
return this.http.post("/api/v2/plays/artifacts", { artifacts });
|
|
2043
|
+
}
|
|
2044
|
+
const compiledArtifacts = await mapWithConcurrency(
|
|
2045
|
+
artifacts,
|
|
2046
|
+
REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY,
|
|
2047
|
+
async (artifact) => ({
|
|
1986
2048
|
...artifact,
|
|
1987
2049
|
compilerManifest: artifact.compilerManifest ?? await this.compilePlayManifest({
|
|
1988
2050
|
name: artifact.name,
|
|
@@ -1990,11 +2052,20 @@ var DeeplineClient = class {
|
|
|
1990
2052
|
sourceFiles: artifact.sourceFiles,
|
|
1991
2053
|
artifact: artifact.artifact
|
|
1992
2054
|
})
|
|
1993
|
-
})
|
|
2055
|
+
})
|
|
1994
2056
|
);
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
2057
|
+
const responses = [];
|
|
2058
|
+
for (const chunk of chunkRegisterPlayArtifacts(compiledArtifacts)) {
|
|
2059
|
+
responses.push(
|
|
2060
|
+
await this.http.post("/api/v2/plays/artifacts", {
|
|
2061
|
+
artifacts: chunk
|
|
2062
|
+
})
|
|
2063
|
+
);
|
|
2064
|
+
}
|
|
2065
|
+
return {
|
|
2066
|
+
success: responses.every((response) => response.success),
|
|
2067
|
+
artifacts: responses.flatMap((response) => response.artifacts)
|
|
2068
|
+
};
|
|
1998
2069
|
}
|
|
1999
2070
|
/**
|
|
2000
2071
|
* Compile a bundled play artifact into the server-side compiler manifest.
|
|
@@ -2967,6 +3038,61 @@ var DeeplineClient = class {
|
|
|
2967
3038
|
// ——————————————————————————————————————————————————————————
|
|
2968
3039
|
// Health
|
|
2969
3040
|
// ——————————————————————————————————————————————————————————
|
|
3041
|
+
/**
|
|
3042
|
+
* Published plans plus the caller's active plan: prices, monthly grant
|
|
3043
|
+
* credits, rollover policy, and which plans are open for subscription.
|
|
3044
|
+
* Prefer `client.billing.plans()`.
|
|
3045
|
+
*
|
|
3046
|
+
* @returns Snake_case catalog from `GET /api/v2/billing/catalog/current`
|
|
3047
|
+
*/
|
|
3048
|
+
async getBillingPlans() {
|
|
3049
|
+
return this.http.get("/api/v2/billing/catalog/current");
|
|
3050
|
+
}
|
|
3051
|
+
/**
|
|
3052
|
+
* Subscription state for the active workspace: active plan, whether a
|
|
3053
|
+
* Stripe subscription backs it, renewal/cancellation facts, and remaining
|
|
3054
|
+
* Deepline credit pools. Prefer `client.billing.subscription.status()`.
|
|
3055
|
+
*
|
|
3056
|
+
* @returns Snake_case subscription status from `GET /api/v2/billing/subscription/status`
|
|
3057
|
+
*/
|
|
3058
|
+
async getBillingSubscriptionStatus() {
|
|
3059
|
+
return this.http.get(
|
|
3060
|
+
"/api/v2/billing/subscription/status"
|
|
3061
|
+
);
|
|
3062
|
+
}
|
|
3063
|
+
/**
|
|
3064
|
+
* Schedule subscription cancellation at period end, or reverse a pending
|
|
3065
|
+
* cancellation with `{ undo: true }`. The customer keeps the cycle they
|
|
3066
|
+
* paid for and every remaining credit — cancellation never claws back
|
|
3067
|
+
* credits. Prefer `client.billing.subscription.cancel(...)`.
|
|
3068
|
+
*
|
|
3069
|
+
* @throws {@link DeeplineError} with `statusCode: 409` when the workspace
|
|
3070
|
+
* has no active subscription, and `statusCode: 502` when Stripe rejects
|
|
3071
|
+
* the update (the server message is preserved).
|
|
3072
|
+
*/
|
|
3073
|
+
async cancelBillingSubscription(options) {
|
|
3074
|
+
return this.http.post(
|
|
3075
|
+
"/api/v2/billing/subscription/cancel",
|
|
3076
|
+
{ action: options?.undo ? "undo_cancel" : "cancel" }
|
|
3077
|
+
);
|
|
3078
|
+
}
|
|
3079
|
+
/**
|
|
3080
|
+
* Customer-facing billing history: subscription invoices plus one-time
|
|
3081
|
+
* credit purchase receipts, newest first, with Stripe-hosted links.
|
|
3082
|
+
* Prefer `client.billing.invoices.list(...)`.
|
|
3083
|
+
*
|
|
3084
|
+
* @param options.limit - Maximum entries to return (server clamps to 1–100, default 24).
|
|
3085
|
+
*/
|
|
3086
|
+
async listBillingInvoices(options) {
|
|
3087
|
+
const params = new URLSearchParams();
|
|
3088
|
+
if (options?.limit !== void 0) {
|
|
3089
|
+
params.set("limit", String(options.limit));
|
|
3090
|
+
}
|
|
3091
|
+
const suffix = Array.from(params).length > 0 ? `?${params.toString()}` : "";
|
|
3092
|
+
return this.http.get(
|
|
3093
|
+
`/api/v2/billing/invoices${suffix}`
|
|
3094
|
+
);
|
|
3095
|
+
}
|
|
2970
3096
|
/**
|
|
2971
3097
|
* Check API connectivity and server health.
|
|
2972
3098
|
*
|
|
@@ -84,6 +84,9 @@ const INCLUDE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
|
|
|
84
84
|
const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
|
|
85
85
|
const V2_EXECUTE_RESPONSE_CONTRACT = 'v2-tool-response';
|
|
86
86
|
const COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1_000];
|
|
87
|
+
const REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
|
|
88
|
+
const REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT = 3;
|
|
89
|
+
const REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES = 2_500_000;
|
|
87
90
|
|
|
88
91
|
function sleep(ms: number): Promise<void> {
|
|
89
92
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -104,6 +107,58 @@ function isTransientCompileManifestError(error: unknown): boolean {
|
|
|
104
107
|
);
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
async function mapWithConcurrency<T, U>(
|
|
111
|
+
items: T[],
|
|
112
|
+
concurrency: number,
|
|
113
|
+
mapper: (item: T, index: number) => Promise<U>,
|
|
114
|
+
): Promise<U[]> {
|
|
115
|
+
const results = new Array<U>(items.length);
|
|
116
|
+
let nextIndex = 0;
|
|
117
|
+
const workerCount = Math.min(Math.max(1, concurrency), items.length);
|
|
118
|
+
await Promise.all(
|
|
119
|
+
Array.from({ length: workerCount }, async () => {
|
|
120
|
+
for (;;) {
|
|
121
|
+
const index = nextIndex;
|
|
122
|
+
nextIndex += 1;
|
|
123
|
+
if (index >= items.length) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
results[index] = await mapper(items[index]!, index);
|
|
127
|
+
}
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
return results;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function jsonUtf8Bytes(value: unknown): number {
|
|
134
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function chunkRegisterPlayArtifacts<T>(artifacts: T[]): T[][] {
|
|
138
|
+
const chunks: T[][] = [];
|
|
139
|
+
let current: T[] = [];
|
|
140
|
+
|
|
141
|
+
for (const artifact of artifacts) {
|
|
142
|
+
const candidate = [...current, artifact];
|
|
143
|
+
const candidateTooLarge =
|
|
144
|
+
candidate.length > REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT ||
|
|
145
|
+
jsonUtf8Bytes({ artifacts: candidate }) >
|
|
146
|
+
REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES;
|
|
147
|
+
if (current.length > 0 && candidateTooLarge) {
|
|
148
|
+
chunks.push(current);
|
|
149
|
+
current = [artifact];
|
|
150
|
+
} else {
|
|
151
|
+
current = candidate;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (current.length > 0) {
|
|
156
|
+
chunks.push(current);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return chunks;
|
|
160
|
+
}
|
|
161
|
+
|
|
107
162
|
type ExecuteToolRawOptions = {
|
|
108
163
|
includeToolMetadata?: boolean;
|
|
109
164
|
};
|
|
@@ -270,6 +325,153 @@ export type RunsNamespace = {
|
|
|
270
325
|
) => Promise<StopPlayRunResult>;
|
|
271
326
|
};
|
|
272
327
|
|
|
328
|
+
/** One credit grant pool reported by the billing subscription status endpoint. */
|
|
329
|
+
export type BillingCreditPool = {
|
|
330
|
+
pool: string;
|
|
331
|
+
credits_remaining: number;
|
|
332
|
+
credits_granted: number;
|
|
333
|
+
source: string;
|
|
334
|
+
cycle_key: string | null;
|
|
335
|
+
effective_at: string;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Subscription state for the active workspace, from
|
|
340
|
+
* `GET /api/v2/billing/subscription/status`. All amounts are Deepline credits
|
|
341
|
+
* and Deepline-facing USD — never provider spend.
|
|
342
|
+
*/
|
|
343
|
+
export type BillingSubscriptionStatus = {
|
|
344
|
+
org_id: string;
|
|
345
|
+
plan_version_id: string;
|
|
346
|
+
plan_name: string;
|
|
347
|
+
plan_family_id: string;
|
|
348
|
+
/** Whether a Stripe subscription backs the active plan. */
|
|
349
|
+
subscribed: boolean;
|
|
350
|
+
price_usd: number | null;
|
|
351
|
+
price_interval: string | null;
|
|
352
|
+
monthly_grant_credits: number;
|
|
353
|
+
assigned_by: string;
|
|
354
|
+
assigned_at: string | null;
|
|
355
|
+
credit_pools: BillingCreditPool[];
|
|
356
|
+
pooled_credits_remaining: number;
|
|
357
|
+
/** End of the current paid period (ISO timestamp), when Stripe is reachable. */
|
|
358
|
+
current_period_end: string | null;
|
|
359
|
+
/** True when a cancellation is already scheduled for period end. */
|
|
360
|
+
cancel_at_period_end: boolean | null;
|
|
361
|
+
stripe_status: string | null;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Result of `POST /api/v2/billing/subscription/cancel`. Cancellation is always
|
|
366
|
+
* at period end: the customer keeps the cycle they paid for and every
|
|
367
|
+
* remaining credit. `undo_cancel` reverses a pending cancellation.
|
|
368
|
+
*/
|
|
369
|
+
export type BillingSubscriptionCancelResult = {
|
|
370
|
+
org_id: string;
|
|
371
|
+
subscription_id: string;
|
|
372
|
+
cancel_at_period_end: boolean;
|
|
373
|
+
current_period_end: string | null;
|
|
374
|
+
status: string;
|
|
375
|
+
message: string;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* One customer-facing billing history entry from
|
|
380
|
+
* `GET /api/v2/billing/invoices`: a subscription invoice or a one-time credit
|
|
381
|
+
* purchase receipt. Amounts are what the customer paid — never provider spend.
|
|
382
|
+
*/
|
|
383
|
+
export type BillingInvoiceEntry = {
|
|
384
|
+
kind: 'invoice' | 'receipt';
|
|
385
|
+
id: string;
|
|
386
|
+
created_at: string;
|
|
387
|
+
description: string;
|
|
388
|
+
amount_cents: number;
|
|
389
|
+
currency: string;
|
|
390
|
+
status: string;
|
|
391
|
+
/** Stripe-hosted page (invoice or card receipt). */
|
|
392
|
+
url: string | null;
|
|
393
|
+
/** Direct PDF when Stripe provides one (invoices only). */
|
|
394
|
+
pdf_url: string | null;
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
export type BillingInvoicesResult = {
|
|
398
|
+
org_id: string;
|
|
399
|
+
entries: BillingInvoiceEntry[];
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
/** One published plan from `GET /api/v2/billing/catalog/current`. */
|
|
403
|
+
export type BillingPlanEntry = {
|
|
404
|
+
plan_family_id: string;
|
|
405
|
+
plan_version_id: string;
|
|
406
|
+
public_name: string;
|
|
407
|
+
price_usd: number | null;
|
|
408
|
+
price_interval: string | null;
|
|
409
|
+
monthly_grant_credits: number;
|
|
410
|
+
rollover: { mode: string; max_credits?: number };
|
|
411
|
+
/** Whether the plan can be purchased via subscription checkout. */
|
|
412
|
+
acquirable: boolean;
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
/** One usage metric published in the billing catalog. */
|
|
416
|
+
export type BillingMetricEntry = {
|
|
417
|
+
id: string;
|
|
418
|
+
name: string;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
/** The caller's active plan as reported by the plans endpoint. */
|
|
422
|
+
export type BillingActivePlan = {
|
|
423
|
+
plan_family_id: string;
|
|
424
|
+
plan_version_id: string;
|
|
425
|
+
public_name: string;
|
|
426
|
+
rate_card_id: string;
|
|
427
|
+
assigned_by: string;
|
|
428
|
+
assigned_at: string | null;
|
|
429
|
+
has_subscription: boolean;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Published plans plus the caller's active plan, from
|
|
434
|
+
* `GET /api/v2/billing/catalog/current`. Answers "what plans exist and what
|
|
435
|
+
* am I on". All amounts are Deepline credits and Deepline-facing USD — never
|
|
436
|
+
* provider spend.
|
|
437
|
+
*/
|
|
438
|
+
export type BillingPlansResult = {
|
|
439
|
+
catalog_id: string;
|
|
440
|
+
catalog_version: string;
|
|
441
|
+
active_plan: BillingActivePlan;
|
|
442
|
+
plans: BillingPlanEntry[];
|
|
443
|
+
metrics: BillingMetricEntry[];
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Public billing namespace exposed as `client.billing`.
|
|
448
|
+
*
|
|
449
|
+
* Carries the durable Deepline billing product model — plans, subscription
|
|
450
|
+
* state, period-end cancellation, and invoice/receipt history — so CLI
|
|
451
|
+
* commands and programmatic callers share the same surface.
|
|
452
|
+
*
|
|
453
|
+
* @sdkReference client 030 client.billing
|
|
454
|
+
*/
|
|
455
|
+
export type BillingNamespace = {
|
|
456
|
+
/** Published plans plus the plan you are on ("what plans exist and what am I on"). */
|
|
457
|
+
plans: () => Promise<BillingPlansResult>;
|
|
458
|
+
subscription: {
|
|
459
|
+
/** Active plan, Stripe subscription state, and remaining credit pools. */
|
|
460
|
+
status: () => Promise<BillingSubscriptionStatus>;
|
|
461
|
+
/**
|
|
462
|
+
* Schedule cancellation at period end (credits are kept), or reverse a
|
|
463
|
+
* pending cancellation with `{ undo: true }`.
|
|
464
|
+
*/
|
|
465
|
+
cancel: (options?: {
|
|
466
|
+
undo?: boolean;
|
|
467
|
+
}) => Promise<BillingSubscriptionCancelResult>;
|
|
468
|
+
};
|
|
469
|
+
invoices: {
|
|
470
|
+
/** Subscription invoices plus credit purchase receipts, newest first. */
|
|
471
|
+
list: (options?: { limit?: number }) => Promise<BillingInvoicesResult>;
|
|
472
|
+
};
|
|
473
|
+
};
|
|
474
|
+
|
|
273
475
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
274
476
|
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
275
477
|
}
|
|
@@ -593,6 +795,8 @@ export class DeeplineClient {
|
|
|
593
795
|
private readonly config: ResolvedConfig;
|
|
594
796
|
/** Canonical run lifecycle namespace backed by `/api/v2/runs`. */
|
|
595
797
|
readonly runs: RunsNamespace;
|
|
798
|
+
/** Billing namespace: subscription status/cancel and invoice history. */
|
|
799
|
+
readonly billing: BillingNamespace;
|
|
596
800
|
|
|
597
801
|
/**
|
|
598
802
|
* Create a low-level SDK client.
|
|
@@ -614,6 +818,16 @@ export class DeeplineClient {
|
|
|
614
818
|
exportDatasetRows: (input) => this.getPlaySheetRows(input),
|
|
615
819
|
stop: (runId, options) => this.stopRun(runId, options),
|
|
616
820
|
};
|
|
821
|
+
this.billing = {
|
|
822
|
+
plans: () => this.getBillingPlans(),
|
|
823
|
+
subscription: {
|
|
824
|
+
status: () => this.getBillingSubscriptionStatus(),
|
|
825
|
+
cancel: (options) => this.cancelBillingSubscription(options),
|
|
826
|
+
},
|
|
827
|
+
invoices: {
|
|
828
|
+
list: (options) => this.listBillingInvoices(options),
|
|
829
|
+
},
|
|
830
|
+
};
|
|
617
831
|
}
|
|
618
832
|
|
|
619
833
|
/** The resolved base URL this client is targeting (e.g. `"http://localhost:3000"`). */
|
|
@@ -1164,8 +1378,13 @@ export class DeeplineClient {
|
|
|
1164
1378
|
triggerBindings?: unknown;
|
|
1165
1379
|
}>;
|
|
1166
1380
|
}> {
|
|
1167
|
-
|
|
1168
|
-
|
|
1381
|
+
if (artifacts.length === 0) {
|
|
1382
|
+
return this.http.post('/api/v2/plays/artifacts', { artifacts });
|
|
1383
|
+
}
|
|
1384
|
+
const compiledArtifacts = await mapWithConcurrency(
|
|
1385
|
+
artifacts,
|
|
1386
|
+
REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY,
|
|
1387
|
+
async (artifact) => ({
|
|
1169
1388
|
...artifact,
|
|
1170
1389
|
compilerManifest:
|
|
1171
1390
|
artifact.compilerManifest ??
|
|
@@ -1175,11 +1394,35 @@ export class DeeplineClient {
|
|
|
1175
1394
|
sourceFiles: artifact.sourceFiles,
|
|
1176
1395
|
artifact: artifact.artifact,
|
|
1177
1396
|
})),
|
|
1178
|
-
})
|
|
1397
|
+
}),
|
|
1179
1398
|
);
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1399
|
+
const responses = [];
|
|
1400
|
+
for (const chunk of chunkRegisterPlayArtifacts(compiledArtifacts)) {
|
|
1401
|
+
responses.push(
|
|
1402
|
+
await this.http.post<{
|
|
1403
|
+
success: boolean;
|
|
1404
|
+
artifacts: Array<{
|
|
1405
|
+
success?: boolean;
|
|
1406
|
+
name?: string;
|
|
1407
|
+
artifactStorageKey: string;
|
|
1408
|
+
artifactMetadata?: Record<string, unknown> | null;
|
|
1409
|
+
staticPipeline?: unknown;
|
|
1410
|
+
definitionId?: string | null;
|
|
1411
|
+
revisionId?: string | null;
|
|
1412
|
+
version?: number | null;
|
|
1413
|
+
liveVersion?: number | null;
|
|
1414
|
+
triggerMetadata?: unknown;
|
|
1415
|
+
triggerBindings?: unknown;
|
|
1416
|
+
}>;
|
|
1417
|
+
}>('/api/v2/plays/artifacts', {
|
|
1418
|
+
artifacts: chunk,
|
|
1419
|
+
}),
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
return {
|
|
1423
|
+
success: responses.every((response) => response.success),
|
|
1424
|
+
artifacts: responses.flatMap((response) => response.artifacts),
|
|
1425
|
+
};
|
|
1183
1426
|
}
|
|
1184
1427
|
|
|
1185
1428
|
/**
|
|
@@ -2420,6 +2663,69 @@ export class DeeplineClient {
|
|
|
2420
2663
|
// Health
|
|
2421
2664
|
// ——————————————————————————————————————————————————————————
|
|
2422
2665
|
|
|
2666
|
+
/**
|
|
2667
|
+
* Published plans plus the caller's active plan: prices, monthly grant
|
|
2668
|
+
* credits, rollover policy, and which plans are open for subscription.
|
|
2669
|
+
* Prefer `client.billing.plans()`.
|
|
2670
|
+
*
|
|
2671
|
+
* @returns Snake_case catalog from `GET /api/v2/billing/catalog/current`
|
|
2672
|
+
*/
|
|
2673
|
+
async getBillingPlans(): Promise<BillingPlansResult> {
|
|
2674
|
+
return this.http.get<BillingPlansResult>('/api/v2/billing/catalog/current');
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
/**
|
|
2678
|
+
* Subscription state for the active workspace: active plan, whether a
|
|
2679
|
+
* Stripe subscription backs it, renewal/cancellation facts, and remaining
|
|
2680
|
+
* Deepline credit pools. Prefer `client.billing.subscription.status()`.
|
|
2681
|
+
*
|
|
2682
|
+
* @returns Snake_case subscription status from `GET /api/v2/billing/subscription/status`
|
|
2683
|
+
*/
|
|
2684
|
+
async getBillingSubscriptionStatus(): Promise<BillingSubscriptionStatus> {
|
|
2685
|
+
return this.http.get<BillingSubscriptionStatus>(
|
|
2686
|
+
'/api/v2/billing/subscription/status',
|
|
2687
|
+
);
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
/**
|
|
2691
|
+
* Schedule subscription cancellation at period end, or reverse a pending
|
|
2692
|
+
* cancellation with `{ undo: true }`. The customer keeps the cycle they
|
|
2693
|
+
* paid for and every remaining credit — cancellation never claws back
|
|
2694
|
+
* credits. Prefer `client.billing.subscription.cancel(...)`.
|
|
2695
|
+
*
|
|
2696
|
+
* @throws {@link DeeplineError} with `statusCode: 409` when the workspace
|
|
2697
|
+
* has no active subscription, and `statusCode: 502` when Stripe rejects
|
|
2698
|
+
* the update (the server message is preserved).
|
|
2699
|
+
*/
|
|
2700
|
+
async cancelBillingSubscription(options?: {
|
|
2701
|
+
undo?: boolean;
|
|
2702
|
+
}): Promise<BillingSubscriptionCancelResult> {
|
|
2703
|
+
return this.http.post<BillingSubscriptionCancelResult>(
|
|
2704
|
+
'/api/v2/billing/subscription/cancel',
|
|
2705
|
+
{ action: options?.undo ? 'undo_cancel' : 'cancel' },
|
|
2706
|
+
);
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
/**
|
|
2710
|
+
* Customer-facing billing history: subscription invoices plus one-time
|
|
2711
|
+
* credit purchase receipts, newest first, with Stripe-hosted links.
|
|
2712
|
+
* Prefer `client.billing.invoices.list(...)`.
|
|
2713
|
+
*
|
|
2714
|
+
* @param options.limit - Maximum entries to return (server clamps to 1–100, default 24).
|
|
2715
|
+
*/
|
|
2716
|
+
async listBillingInvoices(options?: {
|
|
2717
|
+
limit?: number;
|
|
2718
|
+
}): Promise<BillingInvoicesResult> {
|
|
2719
|
+
const params = new URLSearchParams();
|
|
2720
|
+
if (options?.limit !== undefined) {
|
|
2721
|
+
params.set('limit', String(options.limit));
|
|
2722
|
+
}
|
|
2723
|
+
const suffix = Array.from(params).length > 0 ? `?${params.toString()}` : '';
|
|
2724
|
+
return this.http.get<BillingInvoicesResult>(
|
|
2725
|
+
`/api/v2/billing/invoices${suffix}`,
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2423
2729
|
/**
|
|
2424
2730
|
* Check API connectivity and server health.
|
|
2425
2731
|
*
|
|
@@ -42,6 +42,14 @@ interface RequestOptions {
|
|
|
42
42
|
headers?: Record<string, string>;
|
|
43
43
|
/** Per-request timeout override in milliseconds. */
|
|
44
44
|
timeout?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Treat HTTP 403 as a regular API error instead of a generic {@link AuthError}.
|
|
47
|
+
* Use for endpoints that return 403 with a meaningful server error message
|
|
48
|
+
* (e.g. feature-flagged-off billing subscription checkout) so the server
|
|
49
|
+
* message is preserved and surfaced loudly. HTTP 401 still maps to
|
|
50
|
+
* {@link AuthError}.
|
|
51
|
+
*/
|
|
52
|
+
forbiddenAsApiError?: boolean;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
interface StreamOptions {
|
|
@@ -227,7 +235,10 @@ export class HttpClient {
|
|
|
227
235
|
|
|
228
236
|
clearTimeout(timeoutId);
|
|
229
237
|
|
|
230
|
-
if (
|
|
238
|
+
if (
|
|
239
|
+
response.status === 401 ||
|
|
240
|
+
(response.status === 403 && !options?.forbiddenAsApiError)
|
|
241
|
+
) {
|
|
231
242
|
throw new AuthError();
|
|
232
243
|
}
|
|
233
244
|
|
|
@@ -57,6 +57,12 @@
|
|
|
57
57
|
export { DeeplineClient } from './client.js';
|
|
58
58
|
export { RunObserveTransportUnavailableError } from './runs/observe-transport.js';
|
|
59
59
|
export type {
|
|
60
|
+
BillingCreditPool,
|
|
61
|
+
BillingInvoiceEntry,
|
|
62
|
+
BillingInvoicesResult,
|
|
63
|
+
BillingNamespace,
|
|
64
|
+
BillingSubscriptionCancelResult,
|
|
65
|
+
BillingSubscriptionStatus,
|
|
60
66
|
PlayStatus,
|
|
61
67
|
PlaySheetRow,
|
|
62
68
|
PlaySheetRowsResult,
|
|
@@ -59,10 +59,13 @@ export const SDK_RELEASE = {
|
|
|
59
59
|
// preflight (existence, data rows, quotes, duplicate headers), HTML error
|
|
60
60
|
// scrubbing, and word-boundary watch truncation.
|
|
61
61
|
// 0.1.103 ships the refined SDK CLI command surface.
|
|
62
|
-
|
|
62
|
+
// 0.1.104 ships postgres_fast suspension/billing parity and runtime worker hardening.
|
|
63
|
+
// 0.1.105 ships the billing catalog surface: billing plans, subscribe,
|
|
64
|
+
// subscription status/cancel, invoices, and the client.billing namespace.
|
|
65
|
+
version: '0.1.105',
|
|
63
66
|
apiContract: '2026-06-dataset-column-cell-stale-hard-cutover',
|
|
64
67
|
supportPolicy: {
|
|
65
|
-
latest: '0.1.
|
|
68
|
+
latest: '0.1.105',
|
|
66
69
|
minimumSupported: '0.1.53',
|
|
67
70
|
deprecatedBelow: '0.1.53',
|
|
68
71
|
},
|
|
@@ -176,6 +176,32 @@ export function cloneCsvAliasedRow<T extends Record<string, unknown>>(
|
|
|
176
176
|
return cloned;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Plain enumerable clone for durable serialization (sheet writes, JSON
|
|
181
|
+
* payloads). Projected alias fields are normally non-enumerable so they stay
|
|
182
|
+
* out of spreads and Object.keys — but a JSON round-trip would silently drop
|
|
183
|
+
* them. This materializes every projected alias as a visible field and drops
|
|
184
|
+
* the internal `__deepline*` metadata keys.
|
|
185
|
+
*/
|
|
186
|
+
export function toSerializableCsvAliasedRow(
|
|
187
|
+
row: Record<string, unknown>,
|
|
188
|
+
): Record<string, unknown> {
|
|
189
|
+
const out: Record<string, unknown> = {};
|
|
190
|
+
for (const [field, value] of Object.entries(row)) {
|
|
191
|
+
if (field.startsWith('__deepline')) continue;
|
|
192
|
+
out[field] = value;
|
|
193
|
+
}
|
|
194
|
+
const projectedFields = getCsvProjectedFields(row);
|
|
195
|
+
if (projectedFields) {
|
|
196
|
+
const serializedValues = getCsvProjectedValues(row);
|
|
197
|
+
for (const field of projectedFields) {
|
|
198
|
+
if (Object.prototype.hasOwnProperty.call(out, field)) continue;
|
|
199
|
+
out[field] = row[field] ?? serializedValues?.[field];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
|
|
179
205
|
export function stripCsvProjectedFields<T extends Record<string, unknown>>(
|
|
180
206
|
row: T,
|
|
181
207
|
): T {
|
|
@@ -48,7 +48,7 @@ export const PLAY_RUNTIME_PROVIDERS: Record<
|
|
|
48
48
|
runner: PLAY_RUNTIME_BACKENDS.daytona,
|
|
49
49
|
dedup: PLAY_DEDUP_BACKENDS.durableObject,
|
|
50
50
|
artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
|
|
51
|
-
label: '
|
|
51
|
+
label: 'BETA: Postgres Scheduler + warm sandbox runner + DO dedup',
|
|
52
52
|
},
|
|
53
53
|
postgres_fast_sandbox: {
|
|
54
54
|
id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastSandbox,
|
|
@@ -56,7 +56,7 @@ export const PLAY_RUNTIME_PROVIDERS: Record<
|
|
|
56
56
|
runner: PLAY_RUNTIME_BACKENDS.daytona,
|
|
57
57
|
dedup: PLAY_DEDUP_BACKENDS.durableObject,
|
|
58
58
|
artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
|
|
59
|
-
label: '
|
|
59
|
+
label: 'BETA: Postgres Scheduler + warm sandbox runner + DO dedup',
|
|
60
60
|
},
|
|
61
61
|
postgres_fast_workers: {
|
|
62
62
|
id: PLAY_RUNTIME_PROVIDER_IDS.postgresFastWorkers,
|