@vxil/feature-configs 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -3
- package/dist/index.js +37 -18
- package/package.json +1 -1
- package/src/index.ts +36 -18
package/dist/index.d.ts
CHANGED
|
@@ -6,9 +6,12 @@ export * from './canonicalJson.js';
|
|
|
6
6
|
export * from './publicAssets.js';
|
|
7
7
|
export declare const RESERVED_CREDIT_TYPES: ReadonlySet<string>;
|
|
8
8
|
/** A function binding's `retry.maxAttempts` ceiling, and the
|
|
9
|
-
* binding kinds that may carry `retry` — the platform
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* binding kinds that may carry `retry` — every lane the platform delivers
|
|
10
|
+
* through jobs. Since 2026-10-03 (JT-9) that includes `cron` (a failed tick is
|
|
11
|
+
* re-delivered on the ladder; pair it with `overlap: 'skip'` so a retrying
|
|
12
|
+
* tick never runs beside the next one) and `http` (the ASYNC lane only — a
|
|
13
|
+
* synchronous invoke always hands its caller the function's own status).
|
|
14
|
+
* Read by the schema, the deploy clamp and the CLI. */
|
|
12
15
|
export declare const FN_RETRY_MAX_ATTEMPTS = 5;
|
|
13
16
|
export declare const FN_RETRY_BINDING_KINDS: ReadonlySet<string>;
|
|
14
17
|
/** True when a credit_type is a vxil-COGS reserved type (grant/consume/config
|
package/dist/index.js
CHANGED
|
@@ -42,11 +42,14 @@ if (!FormatRegistry.Has('email')) {
|
|
|
42
42
|
// config-write refusal share ONE list. payments-v1/core.ts re-exports these.
|
|
43
43
|
export const RESERVED_CREDIT_TYPES = new Set(['fn_cpu_ms']);
|
|
44
44
|
/** A function binding's `retry.maxAttempts` ceiling, and the
|
|
45
|
-
* binding kinds that may carry `retry` — the platform
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* binding kinds that may carry `retry` — every lane the platform delivers
|
|
46
|
+
* through jobs. Since 2026-10-03 (JT-9) that includes `cron` (a failed tick is
|
|
47
|
+
* re-delivered on the ladder; pair it with `overlap: 'skip'` so a retrying
|
|
48
|
+
* tick never runs beside the next one) and `http` (the ASYNC lane only — a
|
|
49
|
+
* synchronous invoke always hands its caller the function's own status).
|
|
50
|
+
* Read by the schema, the deploy clamp and the CLI. */
|
|
48
51
|
export const FN_RETRY_MAX_ATTEMPTS = 5;
|
|
49
|
-
export const FN_RETRY_BINDING_KINDS = new Set(['queue', 'webhook', 'cmsHook', 'authHook']);
|
|
52
|
+
export const FN_RETRY_BINDING_KINDS = new Set(['queue', 'webhook', 'cmsHook', 'authHook', 'cron', 'http']);
|
|
50
53
|
/** True when a credit_type is a vxil-COGS reserved type (grant/consume/config
|
|
51
54
|
* of which is restricted to internal platform machinery). */
|
|
52
55
|
export function isReservedCreditType(creditType) {
|
|
@@ -341,7 +344,24 @@ export const JobsConfigSchema = Type.Object({
|
|
|
341
344
|
* pathological target (e.g. an always-throwing function) can generate. */
|
|
342
345
|
dlqDailyQuota: Type.Integer({ default: 0, minimum: 0, maximum: 100_000 }),
|
|
343
346
|
schedules: Type.Object({ maxPerTenant: Type.Integer({ default: 50, minimum: 1, maximum: 1000 }) }, { default: {} }),
|
|
344
|
-
concurrency: Type.Object(
|
|
347
|
+
concurrency: Type.Object(
|
|
348
|
+
/** Per-tenant cap on PLAIN runs (queue / cron / event deliveries,
|
|
349
|
+
* incl. platform-delivered function triggers) in flight at once; generation
|
|
350
|
+
* runs have their own `generation.maxConcurrent`. EFFECTIVE value =
|
|
351
|
+
* min(this, the tenant's fair share of the shared delivery consumer): the
|
|
352
|
+
* platform runs at most 75 queue-lane deliveries in flight for ALL tenants
|
|
353
|
+
* together, and one tenant may hold at most 25 of them (jobs-v1 core.ts
|
|
354
|
+
* TENANT_FAIR_SHARE). Values 26..100 still validate (existing configs keep
|
|
355
|
+
* working) but buy nothing past the share. Over-cap runs wait (deferred,
|
|
356
|
+
* never rejected). The schema `description` below is the tenant-facing
|
|
357
|
+
* copy of this (planner catalog, generated config schema) — keep both in
|
|
358
|
+
* step. */
|
|
359
|
+
{
|
|
360
|
+
maxConcurrent: Type.Integer({
|
|
361
|
+
default: 10, minimum: 1, maximum: 100,
|
|
362
|
+
description: 'Plain runs (queued jobs, cron fires, event deliveries, platform-delivered function triggers) delivered at once; generation runs have their own generation.maxConcurrent. Effective at most 25 (the per-project share of the shared delivery capacity): 26..100 validate but buy nothing more. Over-cap runs wait, never rejected.',
|
|
363
|
+
}),
|
|
364
|
+
}, { default: {} }),
|
|
345
365
|
// Generation lifecycle knobs (guide ch. 6, jobs). The defaults and bounds are
|
|
346
366
|
// declared ONCE, as GENERATION_DEFAULTS / GENERATION_BOUNDS below this schema
|
|
347
367
|
// (2026-09-25): jobs-v1's resolveGenerationConfig imports them and clamps a
|
|
@@ -1413,8 +1433,8 @@ export const FunctionsConfigSchema = Type.Object({
|
|
|
1413
1433
|
collection: Type.Optional(Type.String()), // cmsHook: the CMS collection slug
|
|
1414
1434
|
event: Type.Optional(Type.String()), // cmsHook: beforeCreate|beforeUpdate|beforeWrite · authHook: 'user.created'
|
|
1415
1435
|
// (2026-09-25) the per-binding opt-in to re-delivery on
|
|
1416
|
-
// queue / webhook / cmsHook / authHook
|
|
1417
|
-
//
|
|
1436
|
+
// queue / webhook / cmsHook / authHook, and since 2026-10-03 on
|
|
1437
|
+
// cron and http (the async lane only). Absent = the ACK-200 default. The
|
|
1418
1438
|
// receiver answers a failed attempt as an enveloped 503 (ladder)
|
|
1419
1439
|
// and the last one as a terminal 409 (dead + job.dead_lettered);
|
|
1420
1440
|
// effective attempts = min(maxAttempts, jobs.retry.defaultMaxAttempts).
|
|
@@ -2127,9 +2147,8 @@ export function validateFeatureConfig(feature, raw) {
|
|
|
2127
2147
|
if (b.overlap !== undefined && b.kind !== 'cron') {
|
|
2128
2148
|
errs.push(`/functions/${name}/bindings/${i}: 'overlap' applies to cron bindings only (not '${b.kind}')`);
|
|
2129
2149
|
}
|
|
2130
|
-
// retry is an opt-in for the platform-delivered
|
|
2131
|
-
//
|
|
2132
|
-
// tick's retry would overlap the next tick.
|
|
2150
|
+
// retry is an opt-in for the platform-delivered lanes
|
|
2151
|
+
// (FN_RETRY_BINDING_KINDS — every binding kind since JT-9)
|
|
2133
2152
|
if (b.retry !== undefined && !FN_RETRY_BINDING_KINDS.has(b.kind)) {
|
|
2134
2153
|
errs.push(`/functions/${name}/bindings/${i}: 'retry' applies to ${[...FN_RETRY_BINDING_KINDS].join(' | ')} bindings only (not '${b.kind}')`);
|
|
2135
2154
|
}
|
|
@@ -2223,15 +2242,15 @@ export const FEATURE_KEYS = [
|
|
|
2223
2242
|
];
|
|
2224
2243
|
export const FEATURE_HINTS = {
|
|
2225
2244
|
notifications: {
|
|
2226
|
-
whenToUse: 'Sending email (transactional or broadcast) or in-app inbox messages to end-users: welcomes, receipts, reminders, alerts, digests.',
|
|
2245
|
+
whenToUse: 'Sending email (transactional or broadcast) or in-app inbox messages to end-users: welcomes, receipts, reminders, alerts, digests. A send can be scheduled for a known time (send_at), so a one-off reminder needs no job or function.',
|
|
2227
2246
|
signals: ['email', 'notify', 'alert', 'reminder', 'welcome', 'receipt', 'digest', 'inbox'],
|
|
2228
2247
|
notFor: 'Live in-page updates (realtime) or activity timelines (activity-feed).',
|
|
2229
2248
|
dependsOn: [],
|
|
2230
2249
|
},
|
|
2231
2250
|
jobs: {
|
|
2232
|
-
whenToUse: 'Background work: scheduled/cron tasks, delayed
|
|
2233
|
-
signals: ['schedule', 'cron', 'daily', 'background', 'queue', 'later', 'recurring', 'batch'],
|
|
2234
|
-
notFor: 'Simple request-response logic that completes inline.',
|
|
2251
|
+
whenToUse: 'Background work: scheduled/cron tasks, delayed runs, retries, queues, runs that wait for an event, per-user serialisation (concurrency keys), debounced bursts, start deadlines, fan-in (a batch completion event), per-user schedules in their own time zone. Also the bookkeeping for LONG work that runs on the tenant\'s own runtime (renders, transcodes, model calls): a generation run holds reserved credits, a deadline, a signed completion callback and live progress mirrored onto a cms row.',
|
|
2252
|
+
signals: ['schedule', 'cron', 'daily', 'background', 'queue', 'later', 'recurring', 'batch', 'render', 'transcode', 'progress', 'long-running'],
|
|
2253
|
+
notFor: 'Simple request-response logic that completes inline; it is a queue with controls, not a workflow engine, and it never runs the heavy compute itself.',
|
|
2235
2254
|
dependsOn: [],
|
|
2236
2255
|
},
|
|
2237
2256
|
auth: {
|
|
@@ -2247,8 +2266,8 @@ export const FEATURE_HINTS = {
|
|
|
2247
2266
|
dependsOn: [],
|
|
2248
2267
|
},
|
|
2249
2268
|
files: {
|
|
2250
|
-
whenToUse: 'End-users upload or download files/images/documents: avatars, attachments, photos, PDFs, media libraries.',
|
|
2251
|
-
signals: ['upload', 'image', 'photo', 'file', 'attachment', 'document', 'avatar', 'media'],
|
|
2269
|
+
whenToUse: 'End-users upload or download files/images/documents: avatars, attachments, photos, PDFs, media libraries. Media shown publicly (galleries, product photos, video, audio, fonts) is published to a public CDN URL, with named image variant presets such as thumbnails (publicAssets).',
|
|
2270
|
+
signals: ['upload', 'image', 'photo', 'file', 'attachment', 'document', 'avatar', 'media', 'gallery', 'thumbnail', 'video', 'CDN'],
|
|
2252
2271
|
notFor: 'Structured records (cms) or text content authored in-app.',
|
|
2253
2272
|
dependsOn: [],
|
|
2254
2273
|
},
|
|
@@ -2265,7 +2284,7 @@ export const FEATURE_HINTS = {
|
|
|
2265
2284
|
dependsOn: [],
|
|
2266
2285
|
},
|
|
2267
2286
|
cms: {
|
|
2268
|
-
whenToUse: 'The data spine: typed record collections with fields, relations, owner-scoping, draft/publish, and optional keyless public reads. Most apps are, underneath, cms collections.',
|
|
2287
|
+
whenToUse: 'The data spine: typed record collections with fields, relations, owner-scoping, draft/publish, indexed filters, and optional keyless public reads. Most apps are, underneath, cms collections.',
|
|
2269
2288
|
signals: ['store', 'list', 'catalog', 'posts', 'products', 'records', 'items', 'content', 'blog', 'tasks', 'listings'],
|
|
2270
2289
|
notFor: 'End-user identity (auth) or file bytes (files).',
|
|
2271
2290
|
dependsOn: [],
|
|
@@ -2327,7 +2346,7 @@ export const FEATURE_HINTS = {
|
|
|
2327
2346
|
functions: {
|
|
2328
2347
|
whenToUse: 'ONLY for truly-unique server logic no feature or cms rule can express: bespoke sagas, custom integrations over the egress guard, computed endpoints. Prefer features/cms first; functions are the escape hatch.',
|
|
2329
2348
|
signals: ['custom logic', 'custom backend', 'integration with', 'workflow', 'saga'],
|
|
2330
|
-
notFor: 'Anything a shipped feature or a cms lifecycle hook already covers.',
|
|
2349
|
+
notFor: 'Anything a shipped feature or a cms lifecycle hook already covers, and heavy or long compute (renders, ffmpeg, ML) — that runs on the tenant\'s own runtime, tracked by a jobs generation run.',
|
|
2331
2350
|
dependsOn: [],
|
|
2332
2351
|
},
|
|
2333
2352
|
copilot: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vxil/feature-configs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The per-feature configuration schemas and validators behind vxil.config.ts (published for @vxil/cli and @vxil/config).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://vxil.com",
|
package/src/index.ts
CHANGED
|
@@ -46,11 +46,14 @@ if (!FormatRegistry.Has('email')) {
|
|
|
46
46
|
export const RESERVED_CREDIT_TYPES: ReadonlySet<string> = new Set<string>(['fn_cpu_ms']);
|
|
47
47
|
|
|
48
48
|
/** A function binding's `retry.maxAttempts` ceiling, and the
|
|
49
|
-
* binding kinds that may carry `retry` — the platform
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* binding kinds that may carry `retry` — every lane the platform delivers
|
|
50
|
+
* through jobs. Since 2026-10-03 (JT-9) that includes `cron` (a failed tick is
|
|
51
|
+
* re-delivered on the ladder; pair it with `overlap: 'skip'` so a retrying
|
|
52
|
+
* tick never runs beside the next one) and `http` (the ASYNC lane only — a
|
|
53
|
+
* synchronous invoke always hands its caller the function's own status).
|
|
54
|
+
* Read by the schema, the deploy clamp and the CLI. */
|
|
52
55
|
export const FN_RETRY_MAX_ATTEMPTS = 5;
|
|
53
|
-
export const FN_RETRY_BINDING_KINDS: ReadonlySet<string> = new Set(['queue', 'webhook', 'cmsHook', 'authHook']);
|
|
56
|
+
export const FN_RETRY_BINDING_KINDS: ReadonlySet<string> = new Set(['queue', 'webhook', 'cmsHook', 'authHook', 'cron', 'http']);
|
|
54
57
|
|
|
55
58
|
/** True when a credit_type is a vxil-COGS reserved type (grant/consume/config
|
|
56
59
|
* of which is restricted to internal platform machinery). */
|
|
@@ -399,7 +402,23 @@ export const JobsConfigSchema = Type.Object({
|
|
|
399
402
|
{ default: {} },
|
|
400
403
|
),
|
|
401
404
|
concurrency: Type.Object(
|
|
402
|
-
|
|
405
|
+
/** Per-tenant cap on PLAIN runs (queue / cron / event deliveries,
|
|
406
|
+
* incl. platform-delivered function triggers) in flight at once; generation
|
|
407
|
+
* runs have their own `generation.maxConcurrent`. EFFECTIVE value =
|
|
408
|
+
* min(this, the tenant's fair share of the shared delivery consumer): the
|
|
409
|
+
* platform runs at most 75 queue-lane deliveries in flight for ALL tenants
|
|
410
|
+
* together, and one tenant may hold at most 25 of them (jobs-v1 core.ts
|
|
411
|
+
* TENANT_FAIR_SHARE). Values 26..100 still validate (existing configs keep
|
|
412
|
+
* working) but buy nothing past the share. Over-cap runs wait (deferred,
|
|
413
|
+
* never rejected). The schema `description` below is the tenant-facing
|
|
414
|
+
* copy of this (planner catalog, generated config schema) — keep both in
|
|
415
|
+
* step. */
|
|
416
|
+
{
|
|
417
|
+
maxConcurrent: Type.Integer({
|
|
418
|
+
default: 10, minimum: 1, maximum: 100,
|
|
419
|
+
description: 'Plain runs (queued jobs, cron fires, event deliveries, platform-delivered function triggers) delivered at once; generation runs have their own generation.maxConcurrent. Effective at most 25 (the per-project share of the shared delivery capacity): 26..100 validate but buy nothing more. Over-cap runs wait, never rejected.',
|
|
420
|
+
}),
|
|
421
|
+
},
|
|
403
422
|
{ default: {} },
|
|
404
423
|
),
|
|
405
424
|
// Generation lifecycle knobs (guide ch. 6, jobs). The defaults and bounds are
|
|
@@ -1754,8 +1773,8 @@ export const FunctionsConfigSchema = Type.Object({
|
|
|
1754
1773
|
collection: Type.Optional(Type.String()), // cmsHook: the CMS collection slug
|
|
1755
1774
|
event: Type.Optional(Type.String()), // cmsHook: beforeCreate|beforeUpdate|beforeWrite · authHook: 'user.created'
|
|
1756
1775
|
// (2026-09-25) the per-binding opt-in to re-delivery on
|
|
1757
|
-
// queue / webhook / cmsHook / authHook
|
|
1758
|
-
//
|
|
1776
|
+
// queue / webhook / cmsHook / authHook, and since 2026-10-03 on
|
|
1777
|
+
// cron and http (the async lane only). Absent = the ACK-200 default. The
|
|
1759
1778
|
// receiver answers a failed attempt as an enveloped 503 (ladder)
|
|
1760
1779
|
// and the last one as a terminal 409 (dead + job.dead_lettered);
|
|
1761
1780
|
// effective attempts = min(maxAttempts, jobs.retry.defaultMaxAttempts).
|
|
@@ -2567,9 +2586,8 @@ export function validateFeatureConfig(feature: string, raw: unknown): ConfigVali
|
|
|
2567
2586
|
if (b.overlap !== undefined && b.kind !== 'cron') {
|
|
2568
2587
|
errs.push(`/functions/${name}/bindings/${i}: 'overlap' applies to cron bindings only (not '${b.kind}')`);
|
|
2569
2588
|
}
|
|
2570
|
-
// retry is an opt-in for the platform-delivered
|
|
2571
|
-
//
|
|
2572
|
-
// tick's retry would overlap the next tick.
|
|
2589
|
+
// retry is an opt-in for the platform-delivered lanes
|
|
2590
|
+
// (FN_RETRY_BINDING_KINDS — every binding kind since JT-9)
|
|
2573
2591
|
if (b.retry !== undefined && !FN_RETRY_BINDING_KINDS.has(b.kind)) {
|
|
2574
2592
|
errs.push(`/functions/${name}/bindings/${i}: 'retry' applies to ${[...FN_RETRY_BINDING_KINDS].join(' | ')} bindings only (not '${b.kind}')`);
|
|
2575
2593
|
}
|
|
@@ -2683,15 +2701,15 @@ export interface PlannerHint {
|
|
|
2683
2701
|
|
|
2684
2702
|
export const FEATURE_HINTS: Record<FeatureKey, PlannerHint> = {
|
|
2685
2703
|
notifications: {
|
|
2686
|
-
whenToUse: 'Sending email (transactional or broadcast) or in-app inbox messages to end-users: welcomes, receipts, reminders, alerts, digests.',
|
|
2704
|
+
whenToUse: 'Sending email (transactional or broadcast) or in-app inbox messages to end-users: welcomes, receipts, reminders, alerts, digests. A send can be scheduled for a known time (send_at), so a one-off reminder needs no job or function.',
|
|
2687
2705
|
signals: ['email', 'notify', 'alert', 'reminder', 'welcome', 'receipt', 'digest', 'inbox'],
|
|
2688
2706
|
notFor: 'Live in-page updates (realtime) or activity timelines (activity-feed).',
|
|
2689
2707
|
dependsOn: [],
|
|
2690
2708
|
},
|
|
2691
2709
|
jobs: {
|
|
2692
|
-
whenToUse: 'Background work: scheduled/cron tasks, delayed
|
|
2693
|
-
signals: ['schedule', 'cron', 'daily', 'background', 'queue', 'later', 'recurring', 'batch'],
|
|
2694
|
-
notFor: 'Simple request-response logic that completes inline.',
|
|
2710
|
+
whenToUse: 'Background work: scheduled/cron tasks, delayed runs, retries, queues, runs that wait for an event, per-user serialisation (concurrency keys), debounced bursts, start deadlines, fan-in (a batch completion event), per-user schedules in their own time zone. Also the bookkeeping for LONG work that runs on the tenant\'s own runtime (renders, transcodes, model calls): a generation run holds reserved credits, a deadline, a signed completion callback and live progress mirrored onto a cms row.',
|
|
2711
|
+
signals: ['schedule', 'cron', 'daily', 'background', 'queue', 'later', 'recurring', 'batch', 'render', 'transcode', 'progress', 'long-running'],
|
|
2712
|
+
notFor: 'Simple request-response logic that completes inline; it is a queue with controls, not a workflow engine, and it never runs the heavy compute itself.',
|
|
2695
2713
|
dependsOn: [],
|
|
2696
2714
|
},
|
|
2697
2715
|
auth: {
|
|
@@ -2707,8 +2725,8 @@ export const FEATURE_HINTS: Record<FeatureKey, PlannerHint> = {
|
|
|
2707
2725
|
dependsOn: [],
|
|
2708
2726
|
},
|
|
2709
2727
|
files: {
|
|
2710
|
-
whenToUse: 'End-users upload or download files/images/documents: avatars, attachments, photos, PDFs, media libraries.',
|
|
2711
|
-
signals: ['upload', 'image', 'photo', 'file', 'attachment', 'document', 'avatar', 'media'],
|
|
2728
|
+
whenToUse: 'End-users upload or download files/images/documents: avatars, attachments, photos, PDFs, media libraries. Media shown publicly (galleries, product photos, video, audio, fonts) is published to a public CDN URL, with named image variant presets such as thumbnails (publicAssets).',
|
|
2729
|
+
signals: ['upload', 'image', 'photo', 'file', 'attachment', 'document', 'avatar', 'media', 'gallery', 'thumbnail', 'video', 'CDN'],
|
|
2712
2730
|
notFor: 'Structured records (cms) or text content authored in-app.',
|
|
2713
2731
|
dependsOn: [],
|
|
2714
2732
|
},
|
|
@@ -2725,7 +2743,7 @@ export const FEATURE_HINTS: Record<FeatureKey, PlannerHint> = {
|
|
|
2725
2743
|
dependsOn: [],
|
|
2726
2744
|
},
|
|
2727
2745
|
cms: {
|
|
2728
|
-
whenToUse: 'The data spine: typed record collections with fields, relations, owner-scoping, draft/publish, and optional keyless public reads. Most apps are, underneath, cms collections.',
|
|
2746
|
+
whenToUse: 'The data spine: typed record collections with fields, relations, owner-scoping, draft/publish, indexed filters, and optional keyless public reads. Most apps are, underneath, cms collections.',
|
|
2729
2747
|
signals: ['store', 'list', 'catalog', 'posts', 'products', 'records', 'items', 'content', 'blog', 'tasks', 'listings'],
|
|
2730
2748
|
notFor: 'End-user identity (auth) or file bytes (files).',
|
|
2731
2749
|
dependsOn: [],
|
|
@@ -2787,7 +2805,7 @@ export const FEATURE_HINTS: Record<FeatureKey, PlannerHint> = {
|
|
|
2787
2805
|
functions: {
|
|
2788
2806
|
whenToUse: 'ONLY for truly-unique server logic no feature or cms rule can express: bespoke sagas, custom integrations over the egress guard, computed endpoints. Prefer features/cms first; functions are the escape hatch.',
|
|
2789
2807
|
signals: ['custom logic', 'custom backend', 'integration with', 'workflow', 'saga'],
|
|
2790
|
-
notFor: 'Anything a shipped feature or a cms lifecycle hook already covers.',
|
|
2808
|
+
notFor: 'Anything a shipped feature or a cms lifecycle hook already covers, and heavy or long compute (renders, ffmpeg, ML) — that runs on the tenant\'s own runtime, tracked by a jobs generation run.',
|
|
2791
2809
|
dependsOn: [],
|
|
2792
2810
|
},
|
|
2793
2811
|
copilot: {
|