primitive-admin 1.0.53 → 1.0.55
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/README.md +38 -10
- package/dist/bin/primitive.js +8 -0
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/apps.js +54 -2
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/auth.js +16 -6
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/blob-buckets.js +84 -7
- package/dist/src/commands/blob-buckets.js.map +1 -1
- package/dist/src/commands/catalog.js +3 -3
- package/dist/src/commands/catalog.js.map +1 -1
- package/dist/src/commands/collections.js +12 -9
- package/dist/src/commands/collections.js.map +1 -1
- package/dist/src/commands/databases.js +220 -82
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +77 -0
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/group-type-configs.js +1 -9
- package/dist/src/commands/group-type-configs.js.map +1 -1
- package/dist/src/commands/groups.js +12 -6
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/guides.d.ts +161 -0
- package/dist/src/commands/guides.js +502 -84
- package/dist/src/commands/guides.js.map +1 -1
- package/dist/src/commands/integrations.js +2 -2
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/metadata.d.ts +2 -0
- package/dist/src/commands/metadata.js +344 -0
- package/dist/src/commands/metadata.js.map +1 -0
- package/dist/src/commands/prompts.js +2 -2
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/rule-sets.d.ts +1 -0
- package/dist/src/commands/rule-sets.js +25 -3
- package/dist/src/commands/rule-sets.js.map +1 -1
- package/dist/src/commands/scripts.d.ts +2 -0
- package/dist/src/commands/scripts.js +667 -0
- package/dist/src/commands/scripts.js.map +1 -0
- package/dist/src/commands/settings.d.ts +15 -0
- package/dist/src/commands/settings.js +102 -0
- package/dist/src/commands/settings.js.map +1 -0
- package/dist/src/commands/sync-app-settings.d.ts +105 -0
- package/dist/src/commands/sync-app-settings.js +339 -0
- package/dist/src/commands/sync-app-settings.js.map +1 -0
- package/dist/src/commands/sync.d.ts +204 -9
- package/dist/src/commands/sync.js +1706 -371
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/vars.d.ts +8 -0
- package/dist/src/commands/vars.js +110 -0
- package/dist/src/commands/vars.js.map +1 -0
- package/dist/src/commands/webhooks.js +17 -3
- package/dist/src/commands/webhooks.js.map +1 -1
- package/dist/src/commands/workflows.d.ts +30 -0
- package/dist/src/commands/workflows.js +667 -59
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +122 -18
- package/dist/src/lib/api-client.js +131 -2
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +108 -0
- package/dist/src/lib/app-settings-descriptor.js +250 -0
- package/dist/src/lib/app-settings-descriptor.js.map +1 -0
- package/dist/src/lib/batch.d.ts +26 -0
- package/dist/src/lib/batch.js +32 -0
- package/dist/src/lib/batch.js.map +1 -0
- package/dist/src/lib/block-layout.d.ts +160 -0
- package/dist/src/lib/block-layout.js +451 -0
- package/dist/src/lib/block-layout.js.map +1 -0
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +76 -0
- package/dist/src/lib/codegen-shared/generatedFiles.js +144 -0
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +68 -0
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +168 -0
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
- package/dist/src/lib/config-toml.d.ts +10 -0
- package/dist/src/lib/config-toml.js +42 -0
- package/dist/src/lib/config-toml.js.map +1 -0
- package/dist/src/lib/config.d.ts +16 -0
- package/dist/src/lib/config.js +41 -0
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/constants.d.ts +9 -0
- package/dist/src/lib/constants.js +9 -0
- package/dist/src/lib/constants.js.map +1 -1
- package/dist/src/lib/csv.d.ts +1 -2
- package/dist/src/lib/csv.js +3 -8
- package/dist/src/lib/csv.js.map +1 -1
- package/dist/src/lib/db-codegen/dbGenerator.d.ts +21 -65
- package/dist/src/lib/db-codegen/dbGenerator.js +117 -321
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/db-codegen/dbNaming.d.ts +37 -0
- package/dist/src/lib/db-codegen/dbNaming.js +70 -0
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +165 -5
- package/dist/src/lib/db-codegen/dbTemplates.js +292 -16
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTsTypes.d.ts +7 -3
- package/dist/src/lib/db-codegen/dbTsTypes.js +23 -1
- package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +101 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +200 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
- package/dist/src/lib/generated-allowlist.js +43 -0
- package/dist/src/lib/generated-allowlist.js.map +1 -1
- package/dist/src/lib/init-config.js +2 -2
- package/dist/src/lib/init-config.js.map +1 -1
- package/dist/src/lib/output.d.ts +25 -5
- package/dist/src/lib/output.js +32 -4
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/query-operators.d.ts +43 -0
- package/dist/src/lib/query-operators.js +80 -0
- package/dist/src/lib/query-operators.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +68 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js +380 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
- package/dist/src/lib/swift-codegen/generator.d.ts +84 -0
- package/dist/src/lib/swift-codegen/generator.js +178 -0
- package/dist/src/lib/swift-codegen/generator.js.map +1 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
- package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
- package/dist/src/lib/sync-resource-types.d.ts +225 -0
- package/dist/src/lib/sync-resource-types.js +394 -0
- package/dist/src/lib/sync-resource-types.js.map +1 -0
- package/dist/src/lib/toml-database-config.d.ts +10 -19
- package/dist/src/lib/toml-database-config.js +28 -59
- package/dist/src/lib/toml-database-config.js.map +1 -1
- package/dist/src/lib/toml-metadata-config.d.ts +147 -0
- package/dist/src/lib/toml-metadata-config.js +463 -0
- package/dist/src/lib/toml-metadata-config.js.map +1 -0
- package/dist/src/lib/toml-native-form.d.ts +46 -0
- package/dist/src/lib/toml-native-form.js +78 -0
- package/dist/src/lib/toml-native-form.js.map +1 -0
- package/dist/src/lib/toml-params-validator.d.ts +34 -0
- package/dist/src/lib/toml-params-validator.js +118 -3
- package/dist/src/lib/toml-params-validator.js.map +1 -1
- package/dist/src/lib/workflow-apply.d.ts +86 -0
- package/dist/src/lib/workflow-apply.js +127 -0
- package/dist/src/lib/workflow-apply.js.map +1 -0
- package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +129 -0
- package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +269 -0
- package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
- package/dist/src/lib/workflow-codegen/generator.d.ts +87 -0
- package/dist/src/lib/workflow-codegen/generator.js +290 -0
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +85 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js +71 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
- package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
- package/dist/src/lib/workflow-codegen/naming.js +81 -0
- package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
- package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +64 -0
- package/dist/src/lib/workflow-codegen/schemaToTs.js +282 -0
- package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
- package/dist/src/lib/workflow-fragments.js +3 -3
- package/dist/src/lib/workflow-fragments.js.map +1 -1
- package/dist/src/lib/workflow-payload.d.ts +68 -0
- package/dist/src/lib/workflow-payload.js +150 -0
- package/dist/src/lib/workflow-payload.js.map +1 -0
- package/dist/src/lib/workflow-toml-validator.d.ts +1 -1
- package/dist/src/lib/workflow-toml-validator.js +37 -1
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/dist/src/types/index.d.ts +11 -0
- package/dist/src/validators.d.ts +4 -3
- package/dist/src/validators.js +6 -5
- package/dist/src/validators.js.map +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Neutral TOML-form helpers shared by every config serializer that chooses
|
|
3
|
+
* between a native nested-table form and a legacy JSON-string form.
|
|
4
|
+
*
|
|
5
|
+
* These used to live in `toml-database-config.ts`, but that module owns
|
|
6
|
+
* database-operation config specifically; once workflow-schema serialization
|
|
7
|
+
* also needed `canEmitNative` / `FieldForm` / `classifyInlineFieldForm`
|
|
8
|
+
* (issue #1446), keeping them there made a database-specific module double as a
|
|
9
|
+
* generic TOML utility by accident. They now live here so both callers import
|
|
10
|
+
* from a neutral home. `toml-database-config.ts` re-exports them for backwards
|
|
11
|
+
* compatibility with existing importers.
|
|
12
|
+
*/
|
|
13
|
+
export type FieldForm = "native" | "legacy";
|
|
14
|
+
/**
|
|
15
|
+
* Classify a single-line TOML field value (the text after `key = `) as
|
|
16
|
+
* native or legacy form.
|
|
17
|
+
*
|
|
18
|
+
* An inline table (`{ ... }`) or inline array (`[ ... ]`) is native TOML —
|
|
19
|
+
* the structure is written directly, so `sync pull` should re-emit it through
|
|
20
|
+
* the native-emission path rather than collapse it back to an opaque JSON
|
|
21
|
+
* string. A quoted string (`'...'` / `"..."`) is the legacy JSON-string form.
|
|
22
|
+
*
|
|
23
|
+
* This is the fix for issue #1255: previously ANY `definition = <value>`
|
|
24
|
+
* one-liner was classified `legacy`, so an author who wrote the compact
|
|
25
|
+
* inline form `definition = { filter = { "$in" = [1, 2] } }` got an opaque
|
|
26
|
+
* JSON string back on the next pull (churn). Distinguishing the two makes
|
|
27
|
+
* the inline form round-trip stably through the existing native-emission
|
|
28
|
+
* path.
|
|
29
|
+
*/
|
|
30
|
+
export declare function classifyInlineFieldForm(rawValue: string): FieldForm;
|
|
31
|
+
/**
|
|
32
|
+
* Recursively check whether a JS value can be represented in TOML **without
|
|
33
|
+
* data loss**. Returns null if OK, a reason string otherwise.
|
|
34
|
+
*
|
|
35
|
+
* This is a data-loss guard, not a "native TOML" gate. The config round-trip
|
|
36
|
+
* serializes with `smol-toml` (TOML 1.0), which handles heterogeneous arrays,
|
|
37
|
+
* so the only values that still can't be emitted are the ones every TOML
|
|
38
|
+
* serializer silently drops:
|
|
39
|
+
* - `null` (TOML has no null — the key would vanish on write).
|
|
40
|
+
* - `undefined` (same — the key would vanish).
|
|
41
|
+
* - arrays containing `null` (the element would vanish, shifting the array).
|
|
42
|
+
*
|
|
43
|
+
* Heterogeneous arrays (mixed TOML types) are representable and are NOT
|
|
44
|
+
* flagged — that fallback was removed in issue #1450.
|
|
45
|
+
*/
|
|
46
|
+
export declare function canEmitNative(value: any): string | null;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Neutral TOML-form helpers shared by every config serializer that chooses
|
|
3
|
+
* between a native nested-table form and a legacy JSON-string form.
|
|
4
|
+
*
|
|
5
|
+
* These used to live in `toml-database-config.ts`, but that module owns
|
|
6
|
+
* database-operation config specifically; once workflow-schema serialization
|
|
7
|
+
* also needed `canEmitNative` / `FieldForm` / `classifyInlineFieldForm`
|
|
8
|
+
* (issue #1446), keeping them there made a database-specific module double as a
|
|
9
|
+
* generic TOML utility by accident. They now live here so both callers import
|
|
10
|
+
* from a neutral home. `toml-database-config.ts` re-exports them for backwards
|
|
11
|
+
* compatibility with existing importers.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Classify a single-line TOML field value (the text after `key = `) as
|
|
15
|
+
* native or legacy form.
|
|
16
|
+
*
|
|
17
|
+
* An inline table (`{ ... }`) or inline array (`[ ... ]`) is native TOML —
|
|
18
|
+
* the structure is written directly, so `sync pull` should re-emit it through
|
|
19
|
+
* the native-emission path rather than collapse it back to an opaque JSON
|
|
20
|
+
* string. A quoted string (`'...'` / `"..."`) is the legacy JSON-string form.
|
|
21
|
+
*
|
|
22
|
+
* This is the fix for issue #1255: previously ANY `definition = <value>`
|
|
23
|
+
* one-liner was classified `legacy`, so an author who wrote the compact
|
|
24
|
+
* inline form `definition = { filter = { "$in" = [1, 2] } }` got an opaque
|
|
25
|
+
* JSON string back on the next pull (churn). Distinguishing the two makes
|
|
26
|
+
* the inline form round-trip stably through the existing native-emission
|
|
27
|
+
* path.
|
|
28
|
+
*/
|
|
29
|
+
export function classifyInlineFieldForm(rawValue) {
|
|
30
|
+
const trimmed = rawValue.trimStart();
|
|
31
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("["))
|
|
32
|
+
return "native";
|
|
33
|
+
return "legacy";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Recursively check whether a JS value can be represented in TOML **without
|
|
37
|
+
* data loss**. Returns null if OK, a reason string otherwise.
|
|
38
|
+
*
|
|
39
|
+
* This is a data-loss guard, not a "native TOML" gate. The config round-trip
|
|
40
|
+
* serializes with `smol-toml` (TOML 1.0), which handles heterogeneous arrays,
|
|
41
|
+
* so the only values that still can't be emitted are the ones every TOML
|
|
42
|
+
* serializer silently drops:
|
|
43
|
+
* - `null` (TOML has no null — the key would vanish on write).
|
|
44
|
+
* - `undefined` (same — the key would vanish).
|
|
45
|
+
* - arrays containing `null` (the element would vanish, shifting the array).
|
|
46
|
+
*
|
|
47
|
+
* Heterogeneous arrays (mixed TOML types) are representable and are NOT
|
|
48
|
+
* flagged — that fallback was removed in issue #1450.
|
|
49
|
+
*/
|
|
50
|
+
export function canEmitNative(value) {
|
|
51
|
+
if (value === null)
|
|
52
|
+
return "value is null";
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
return "value is undefined";
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
for (const item of value) {
|
|
57
|
+
if (item === null)
|
|
58
|
+
return "array contains null";
|
|
59
|
+
}
|
|
60
|
+
for (const item of value) {
|
|
61
|
+
const sub = canEmitNative(item);
|
|
62
|
+
if (sub)
|
|
63
|
+
return sub;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "object") {
|
|
68
|
+
for (const v of Object.values(value)) {
|
|
69
|
+
const sub = canEmitNative(v);
|
|
70
|
+
if (sub)
|
|
71
|
+
return sub;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
// primitives: string, number, boolean.
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=toml-native-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toml-native-form.js","sourceRoot":"","sources":["../../../src/lib/toml-native-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;IACrC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACxE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,KAAU;IACtC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,eAAe,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,oBAAoB,CAAC;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,qBAAqB,CAAC;QAClD,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAC7B,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,uCAAuC;IACvC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -47,6 +47,33 @@ export interface ValidationResult {
|
|
|
47
47
|
* doc-comment for the rationale.
|
|
48
48
|
*/
|
|
49
49
|
export declare function collectParamRefs(value: any): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Collect bare `params.X` references from a CEL string (issue #1239).
|
|
52
|
+
*
|
|
53
|
+
* Access rules reference operation params with the bare `params.X` form (no
|
|
54
|
+
* `$` prefix), unlike `definition`, which uses `$params.X` (scanned by
|
|
55
|
+
* {@link collectParamRefs}). This helper feeds the operation's `access` CEL
|
|
56
|
+
* and each per-param `access` CEL into the "referenced" set so a param used
|
|
57
|
+
* only by an access rule is not wrongly flagged "declared but not referenced".
|
|
58
|
+
*
|
|
59
|
+
* Supported forms, all whitespace-tolerant:
|
|
60
|
+
* - dot notation: `params.claimedUserId`, `params . claimedUserId`
|
|
61
|
+
* - dot path: `params.config.subField` → first segment `config`
|
|
62
|
+
* - bracket notation: `params["claimedUserId"]`, `params['claimedUserId']`
|
|
63
|
+
*
|
|
64
|
+
* Word-boundary guard: a `params` preceded by an identifier char, `$`, or `.`
|
|
65
|
+
* is NOT a match, so `$params.x` (definition syntax), `myparams.x`, and a
|
|
66
|
+
* dotted member access like `database.metadata.params.userId` are ignored —
|
|
67
|
+
* `params` only counts as the params root when it's a standalone root
|
|
68
|
+
* identifier. To avoid counting a `params.` that merely appears inside a quoted
|
|
69
|
+
* string literal (e.g. `note == "see params.docs"`), bracket keys are scanned
|
|
70
|
+
* first (they legitimately contain quotes), then string literals are stripped
|
|
71
|
+
* before the dot-notation scan.
|
|
72
|
+
*
|
|
73
|
+
* Purely additive: this only grows the referenced set, loosening the soft
|
|
74
|
+
* warning. The blocking `$params` error path is untouched.
|
|
75
|
+
*/
|
|
76
|
+
export declare function collectCelParamRefs(cel: any): string[];
|
|
50
77
|
/**
|
|
51
78
|
* Normalize a `params` value (object, array, or JSON string) into the
|
|
52
79
|
* set of declared param names.
|
|
@@ -74,6 +101,13 @@ export interface ValidateOptions {
|
|
|
74
101
|
name: string;
|
|
75
102
|
definition: any;
|
|
76
103
|
params?: any;
|
|
104
|
+
/**
|
|
105
|
+
* The operation-level `access` CEL rule, if any (issue #1239). Params
|
|
106
|
+
* referenced here via bare `params.X` count as "referenced" so they are
|
|
107
|
+
* not wrongly flagged "declared but not referenced". May be null/absent
|
|
108
|
+
* when the operation inherits the type's `defaultAccess`.
|
|
109
|
+
*/
|
|
110
|
+
access?: any;
|
|
77
111
|
}>;
|
|
78
112
|
}
|
|
79
113
|
/**
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* `$params.config.subKey` without listing every sub-field
|
|
30
30
|
* individually (review feedback r3246635661).
|
|
31
31
|
*/
|
|
32
|
+
import { collectUnknownOperators } from "./query-operators.js";
|
|
32
33
|
/**
|
|
33
34
|
* Walk an arbitrary JSON-ish value and collect `$params.X` references
|
|
34
35
|
* found in string-valued leaves, returning only the first dotted segment
|
|
@@ -58,6 +59,88 @@ export function collectParamRefs(value) {
|
|
|
58
59
|
}
|
|
59
60
|
return refs;
|
|
60
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Collect bare `params.X` references from a CEL string (issue #1239).
|
|
64
|
+
*
|
|
65
|
+
* Access rules reference operation params with the bare `params.X` form (no
|
|
66
|
+
* `$` prefix), unlike `definition`, which uses `$params.X` (scanned by
|
|
67
|
+
* {@link collectParamRefs}). This helper feeds the operation's `access` CEL
|
|
68
|
+
* and each per-param `access` CEL into the "referenced" set so a param used
|
|
69
|
+
* only by an access rule is not wrongly flagged "declared but not referenced".
|
|
70
|
+
*
|
|
71
|
+
* Supported forms, all whitespace-tolerant:
|
|
72
|
+
* - dot notation: `params.claimedUserId`, `params . claimedUserId`
|
|
73
|
+
* - dot path: `params.config.subField` → first segment `config`
|
|
74
|
+
* - bracket notation: `params["claimedUserId"]`, `params['claimedUserId']`
|
|
75
|
+
*
|
|
76
|
+
* Word-boundary guard: a `params` preceded by an identifier char, `$`, or `.`
|
|
77
|
+
* is NOT a match, so `$params.x` (definition syntax), `myparams.x`, and a
|
|
78
|
+
* dotted member access like `database.metadata.params.userId` are ignored —
|
|
79
|
+
* `params` only counts as the params root when it's a standalone root
|
|
80
|
+
* identifier. To avoid counting a `params.` that merely appears inside a quoted
|
|
81
|
+
* string literal (e.g. `note == "see params.docs"`), bracket keys are scanned
|
|
82
|
+
* first (they legitimately contain quotes), then string literals are stripped
|
|
83
|
+
* before the dot-notation scan.
|
|
84
|
+
*
|
|
85
|
+
* Purely additive: this only grows the referenced set, loosening the soft
|
|
86
|
+
* warning. The blocking `$params` error path is untouched.
|
|
87
|
+
*/
|
|
88
|
+
export function collectCelParamRefs(cel) {
|
|
89
|
+
if (typeof cel !== "string" || cel.length === 0)
|
|
90
|
+
return [];
|
|
91
|
+
const refs = [];
|
|
92
|
+
// Bracket notation: params["X"] / params['X']. Run before stripping string
|
|
93
|
+
// literals so the quoted key survives.
|
|
94
|
+
const bracketRe = /(?<![\w$.])params\s*\[\s*["']([^"']+)["']\s*\]/g;
|
|
95
|
+
let m;
|
|
96
|
+
while ((m = bracketRe.exec(cel)) !== null) {
|
|
97
|
+
const first = m[1].split(/[.\[]/)[0];
|
|
98
|
+
if (first)
|
|
99
|
+
refs.push(first);
|
|
100
|
+
}
|
|
101
|
+
// Drop string literals so `params.` inside a quoted string is not counted.
|
|
102
|
+
const withoutStrings = cel.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g, "");
|
|
103
|
+
// Dot notation: params.X (first segment only, mirroring collectParamRefs).
|
|
104
|
+
const dotRe = /(?<![\w$.])params\s*\.\s*([A-Za-z_$][\w$]*)/g;
|
|
105
|
+
while ((m = dotRe.exec(withoutStrings)) !== null) {
|
|
106
|
+
refs.push(m[1]);
|
|
107
|
+
}
|
|
108
|
+
return refs;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Collect the per-param `access` CEL strings from an operation's `params`
|
|
112
|
+
* value (object, array, or JSON string form). Used by issue #1239 to count
|
|
113
|
+
* params referenced only inside another param's `access` rule.
|
|
114
|
+
*/
|
|
115
|
+
function collectParamAccessCels(params) {
|
|
116
|
+
const cels = [];
|
|
117
|
+
if (params == null)
|
|
118
|
+
return cels;
|
|
119
|
+
let value = params;
|
|
120
|
+
if (typeof value === "string") {
|
|
121
|
+
try {
|
|
122
|
+
value = JSON.parse(value);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return cels;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (Array.isArray(value)) {
|
|
129
|
+
for (const row of value) {
|
|
130
|
+
if (row && typeof row === "object" && typeof row.access === "string") {
|
|
131
|
+
cels.push(row.access);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (typeof value === "object" && value !== null) {
|
|
136
|
+
for (const entry of Object.values(value)) {
|
|
137
|
+
if (entry && typeof entry === "object" && typeof entry.access === "string") {
|
|
138
|
+
cels.push(entry.access);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return cels;
|
|
143
|
+
}
|
|
61
144
|
/**
|
|
62
145
|
* Normalize a `params` value (object, array, or JSON string) into the
|
|
63
146
|
* set of declared param names.
|
|
@@ -146,9 +229,24 @@ export function validateOperations(opts) {
|
|
|
146
229
|
if (!op || !op.name)
|
|
147
230
|
continue;
|
|
148
231
|
const declared = declaredParamNames(op.params);
|
|
149
|
-
|
|
232
|
+
// `definitionRefs` drives the BLOCKING error loop and must stay limited to
|
|
233
|
+
// `$params.X` references inside `definition` — access CEL refs are NOT
|
|
234
|
+
// declarations, so they must never produce an "undeclared" error.
|
|
235
|
+
const definitionRefs = new Set(collectParamRefs(op.definition));
|
|
236
|
+
// Issue #1239: a param referenced only by an access CEL rule (bare
|
|
237
|
+
// `params.X`) is still referenced. The "declared but not referenced"
|
|
238
|
+
// warning uses a wider set that also counts the operation-level `access`
|
|
239
|
+
// and each per-param `access` CEL. Purely additive — the blocking error
|
|
240
|
+
// path below is built only from `definitionRefs`.
|
|
241
|
+
const referenced = new Set(definitionRefs);
|
|
242
|
+
for (const ref of collectCelParamRefs(op.access))
|
|
243
|
+
referenced.add(ref);
|
|
244
|
+
for (const cel of collectParamAccessCels(op.params)) {
|
|
245
|
+
for (const ref of collectCelParamRefs(cel))
|
|
246
|
+
referenced.add(ref);
|
|
247
|
+
}
|
|
150
248
|
const line = locateOperationLine(opts.rawToml, op.name);
|
|
151
|
-
for (const ref of
|
|
249
|
+
for (const ref of definitionRefs) {
|
|
152
250
|
if (!declared.has(ref)) {
|
|
153
251
|
errors.push({
|
|
154
252
|
file: opts.filePath,
|
|
@@ -159,7 +257,7 @@ export function validateOperations(opts) {
|
|
|
159
257
|
}
|
|
160
258
|
}
|
|
161
259
|
for (const name of declared) {
|
|
162
|
-
if (!
|
|
260
|
+
if (!referenced.has(name)) {
|
|
163
261
|
warnings.push({
|
|
164
262
|
file: opts.filePath,
|
|
165
263
|
line,
|
|
@@ -168,6 +266,23 @@ export function validateOperations(opts) {
|
|
|
168
266
|
});
|
|
169
267
|
}
|
|
170
268
|
}
|
|
269
|
+
// Issue #1255 (Fork 4): warn on unknown filter operators. The server only
|
|
270
|
+
// checks that `filter` is an object at push time, so a typo like
|
|
271
|
+
// `$gt` → `$gte` or an invented `$foo` slips through and throws
|
|
272
|
+
// `InvalidOperatorError` only at query execution. We warn (not error) to
|
|
273
|
+
// avoid CLI/server divergence — the operator set could drift, and the
|
|
274
|
+
// server stays authoritative.
|
|
275
|
+
const filter = op.definition && typeof op.definition === "object"
|
|
276
|
+
? op.definition.filter
|
|
277
|
+
: undefined;
|
|
278
|
+
for (const badOp of collectUnknownOperators(filter)) {
|
|
279
|
+
warnings.push({
|
|
280
|
+
file: opts.filePath,
|
|
281
|
+
line,
|
|
282
|
+
op: op.name,
|
|
283
|
+
message: `unknown filter operator '${badOp}' in operation '${op.name}' — not a recognized query operator; it will fail at query execution`,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
171
286
|
}
|
|
172
287
|
return { errors, warnings };
|
|
173
288
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toml-params-validator.js","sourceRoot":"","sources":["../../../src/lib/toml-params-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;
|
|
1
|
+
{"version":3,"file":"toml-params-validator.js","sourceRoot":"","sources":["../../../src/lib/toml-params-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared "apply a TOML body to an existing workflow" helper.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the `sync push` update-existing path (#1249, Fork 4) so that
|
|
5
|
+
* both `sync push` and `workflows update --from-file` push a revised body the
|
|
6
|
+
* same way. A second inlined copy would regress #807: the update is
|
|
7
|
+
* ordering-sensitive and a naive metadata-then-body sequence rejects valid
|
|
8
|
+
* sync-callable edits.
|
|
9
|
+
*
|
|
10
|
+
* Ordering invariant (#807 / codex review):
|
|
11
|
+
* 1. metadata PATCH — WITHOUT `syncCallable`. The server re-validates
|
|
12
|
+
* `syncCallable: true` against the workflow's CURRENTLY-active server
|
|
13
|
+
* steps (`loadCurrentActiveSteps`, src/admin-api.ts:4734), not the steps
|
|
14
|
+
* being pushed in the same call. So enabling sync-callable in the first
|
|
15
|
+
* PATCH would validate against the stale active steps and be rejected.
|
|
16
|
+
* 2. body write — steps to the active config (config-model) or the legacy
|
|
17
|
+
* draft slot (no active config).
|
|
18
|
+
* 3. a SECOND `syncCallable` PATCH — issued AFTER the new steps are active,
|
|
19
|
+
* so it validates against the new (compatible) steps.
|
|
20
|
+
*/
|
|
21
|
+
import type { ApiClient } from "./api-client.js";
|
|
22
|
+
import { safeJsonParse } from "./workflow-payload.js";
|
|
23
|
+
export { safeJsonParse };
|
|
24
|
+
export interface ApplyWorkflowBodyOptions {
|
|
25
|
+
/** Optimistic-concurrency guard for the metadata + syncCallable PATCHes. */
|
|
26
|
+
expectedModifiedAt?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Active config to overwrite in place (config-model workflows). When absent,
|
|
29
|
+
* the body falls back to the legacy draft slot — non-live for config-model
|
|
30
|
+
* workflows, which the server rejects with 409 WORKFLOW_CONFIG_MODEL.
|
|
31
|
+
*/
|
|
32
|
+
activeConfigId?: string;
|
|
33
|
+
/** When true, skip the optimistic-concurrency check (mirrors `--force`). */
|
|
34
|
+
force?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface ApplyWorkflowBodyResult {
|
|
37
|
+
/** The freshest workflow `modifiedAt` after all PATCHes (for sync state). */
|
|
38
|
+
latestModifiedAt?: string;
|
|
39
|
+
/** Which slot the steps landed in: "active config" or "draft (legacy)". */
|
|
40
|
+
updateSlotLabel: string;
|
|
41
|
+
/** A fresh `getWorkflow` result so callers can read back configs/state. */
|
|
42
|
+
fullWorkflow: any;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Apply a parsed workflow body (metadata + steps) to an existing workflow,
|
|
46
|
+
* preserving the key/id. `workflow` is the TOML's `[workflow]` table (already
|
|
47
|
+
* merged with any explicit CLI flag overrides by the caller); `steps` is the
|
|
48
|
+
* TOML's `steps` array. The function performs the three-step ordered update
|
|
49
|
+
* and returns the latest `modifiedAt`, the slot label, and a fresh workflow.
|
|
50
|
+
*/
|
|
51
|
+
export declare function applyWorkflowBody(client: ApiClient, appId: string, workflowId: string, workflow: any, steps: any[], opts?: ApplyWorkflowBodyOptions): Promise<ApplyWorkflowBodyResult>;
|
|
52
|
+
/**
|
|
53
|
+
* #1232 — parse the `workflows update --capabilities` flag into the array the
|
|
54
|
+
* server's update handler expects. This is the CLI fallback the issue asked
|
|
55
|
+
* for ("workflows update has no capability flag"): a grant/revoke channel for
|
|
56
|
+
* an existing workflow, since `sync push` create deliberately does not forward
|
|
57
|
+
* capabilities (#1233, Q2) and there was otherwise no way to set them on an
|
|
58
|
+
* existing workflow.
|
|
59
|
+
*
|
|
60
|
+
* Semantics (mirrors how the server normalizes the field):
|
|
61
|
+
* --capabilities membership → ["membership"] (grant)
|
|
62
|
+
* --capabilities membership,secrets → ["membership","secrets"]
|
|
63
|
+
* --capabilities " membership , x " → ["membership","x"] (trimmed)
|
|
64
|
+
* --capabilities "" → [] (revoke all;
|
|
65
|
+
* server stores empty as null)
|
|
66
|
+
*
|
|
67
|
+
* The set of grantable capability names ("membership" / "secrets") is validated
|
|
68
|
+
* server-side by `validateWorkflowIdentityConfig`; the CLI intentionally does
|
|
69
|
+
* NOT duplicate that allowlist so it can't drift from the server. An unknown
|
|
70
|
+
* name is surfaced via the server's structured `details[]` error.
|
|
71
|
+
*
|
|
72
|
+
* The caller applies presence-guarded plumbing (`options.capabilities !==
|
|
73
|
+
* undefined`) so an omitted flag never reaches the payload — the server's
|
|
74
|
+
* `hasOwnProperty` guard then leaves the existing grant untouched.
|
|
75
|
+
*/
|
|
76
|
+
export declare function parseCapabilitiesFlag(value: string): string[];
|
|
77
|
+
/**
|
|
78
|
+
* Fork 2 (#1249): a TOML pushed at a specific `<id>` may also declare a `key` /
|
|
79
|
+
* `workflowKey`. If it differs from the target's actual key, that's almost
|
|
80
|
+
* certainly the wrong file — error rather than silently ignoring it. An absent
|
|
81
|
+
* TOML key is advisory and allowed (the operation targets `<id>`).
|
|
82
|
+
*
|
|
83
|
+
* Returns an error message string when there is a mismatch, otherwise null.
|
|
84
|
+
* Pure function for unit testing.
|
|
85
|
+
*/
|
|
86
|
+
export declare function workflowKeyMismatchError(tomlWorkflow: any, existingWorkflowKey: string | undefined): string | null;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared "apply a TOML body to an existing workflow" helper.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the `sync push` update-existing path (#1249, Fork 4) so that
|
|
5
|
+
* both `sync push` and `workflows update --from-file` push a revised body the
|
|
6
|
+
* same way. A second inlined copy would regress #807: the update is
|
|
7
|
+
* ordering-sensitive and a naive metadata-then-body sequence rejects valid
|
|
8
|
+
* sync-callable edits.
|
|
9
|
+
*
|
|
10
|
+
* Ordering invariant (#807 / codex review):
|
|
11
|
+
* 1. metadata PATCH — WITHOUT `syncCallable`. The server re-validates
|
|
12
|
+
* `syncCallable: true` against the workflow's CURRENTLY-active server
|
|
13
|
+
* steps (`loadCurrentActiveSteps`, src/admin-api.ts:4734), not the steps
|
|
14
|
+
* being pushed in the same call. So enabling sync-callable in the first
|
|
15
|
+
* PATCH would validate against the stale active steps and be rejected.
|
|
16
|
+
* 2. body write — steps to the active config (config-model) or the legacy
|
|
17
|
+
* draft slot (no active config).
|
|
18
|
+
* 3. a SECOND `syncCallable` PATCH — issued AFTER the new steps are active,
|
|
19
|
+
* so it validates against the new (compatible) steps.
|
|
20
|
+
*/
|
|
21
|
+
import { buildWorkflowPayloadFromToml, safeJsonParse } from "./workflow-payload.js";
|
|
22
|
+
// #1177: `safeJsonParse` now lives in the shared `workflow-payload` lib module
|
|
23
|
+
// (the builder needs it too); re-exported here so existing importers of this
|
|
24
|
+
// module keep working. Both `cli/src/lib` modules; no dep-direction problem.
|
|
25
|
+
export { safeJsonParse };
|
|
26
|
+
/**
|
|
27
|
+
* Apply a parsed workflow body (metadata + steps) to an existing workflow,
|
|
28
|
+
* preserving the key/id. `workflow` is the TOML's `[workflow]` table (already
|
|
29
|
+
* merged with any explicit CLI flag overrides by the caller); `steps` is the
|
|
30
|
+
* TOML's `steps` array. The function performs the three-step ordered update
|
|
31
|
+
* and returns the latest `modifiedAt`, the slot label, and a fresh workflow.
|
|
32
|
+
*/
|
|
33
|
+
export async function applyWorkflowBody(client, appId, workflowId, workflow, steps, opts = {}) {
|
|
34
|
+
const { expectedModifiedAt, activeConfigId, force } = opts;
|
|
35
|
+
// 1. Metadata PATCH — note: NO `syncCallable` here (deferred to step 3). The
|
|
36
|
+
// shared builder (#1177, `mode: "update"`) omits `syncCallable` for exactly
|
|
37
|
+
// this reason and applies the presence-aware clear-vs-leave semantics for
|
|
38
|
+
// `accessRule` / `runAs` / `capabilities` / schemas. `requiresClientApply`
|
|
39
|
+
// has no step-dependent validation, so the builder keeps it here. The
|
|
40
|
+
// `metadataManifest` declared-access manifest (#1304) is call-site-specific
|
|
41
|
+
// and attached below, not owned by the shared builder.
|
|
42
|
+
const updated = await client.updateWorkflow(appId, workflowId, {
|
|
43
|
+
...buildWorkflowPayloadFromToml(workflow, { mode: "update" }),
|
|
44
|
+
// #1304 (P-C): declared-access manifest. Absent key → undefined (server's
|
|
45
|
+
// hasOwnProperty guard leaves it untouched); a parsed value/null is
|
|
46
|
+
// forwarded so a pull → push round-trips it (null clears). `sync push`
|
|
47
|
+
// always attaches this (null when the TOML drops `[metadata]`); the
|
|
48
|
+
// `workflows update --from-file` caller may leave it undefined.
|
|
49
|
+
metadataManifest: workflow.metadataManifest !== undefined ? workflow.metadataManifest : undefined,
|
|
50
|
+
}, expectedModifiedAt);
|
|
51
|
+
// The first PATCH bumps `modifiedAt`; the syncCallable PATCH (if any) bumps
|
|
52
|
+
// it again. The config/step update does NOT touch the workflow definition's
|
|
53
|
+
// `modifiedAt`.
|
|
54
|
+
let latestModifiedAt = updated?.workflow?.modifiedAt;
|
|
55
|
+
// 2. Body write — active config (config-model) or legacy draft slot.
|
|
56
|
+
let updateSlotLabel = "active config";
|
|
57
|
+
if (activeConfigId) {
|
|
58
|
+
await client.updateWorkflowConfig(appId, workflowId, activeConfigId, { steps });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
await client.updateWorkflowDraft(appId, workflowId, {
|
|
62
|
+
steps,
|
|
63
|
+
inputSchema: workflow.inputSchema ? safeJsonParse(workflow.inputSchema) : null,
|
|
64
|
+
});
|
|
65
|
+
updateSlotLabel = "draft (legacy)";
|
|
66
|
+
}
|
|
67
|
+
// 3. Deferred `syncCallable` PATCH — now that the new steps are active (#807).
|
|
68
|
+
// Only sent when the TOML actually carries the key; an absent key stays
|
|
69
|
+
// `undefined` and the call is skipped, preserving no-clobber discipline.
|
|
70
|
+
if (workflow.syncCallable !== undefined) {
|
|
71
|
+
const syncCallableUpdated = await client.updateWorkflow(appId, workflowId, { syncCallable: workflow.syncCallable }, force ? undefined : latestModifiedAt);
|
|
72
|
+
if (syncCallableUpdated?.workflow?.modifiedAt) {
|
|
73
|
+
latestModifiedAt = syncCallableUpdated.workflow.modifiedAt;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const fullWorkflow = await client.getWorkflow(appId, workflowId);
|
|
77
|
+
return { latestModifiedAt, updateSlotLabel, fullWorkflow };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* #1232 — parse the `workflows update --capabilities` flag into the array the
|
|
81
|
+
* server's update handler expects. This is the CLI fallback the issue asked
|
|
82
|
+
* for ("workflows update has no capability flag"): a grant/revoke channel for
|
|
83
|
+
* an existing workflow, since `sync push` create deliberately does not forward
|
|
84
|
+
* capabilities (#1233, Q2) and there was otherwise no way to set them on an
|
|
85
|
+
* existing workflow.
|
|
86
|
+
*
|
|
87
|
+
* Semantics (mirrors how the server normalizes the field):
|
|
88
|
+
* --capabilities membership → ["membership"] (grant)
|
|
89
|
+
* --capabilities membership,secrets → ["membership","secrets"]
|
|
90
|
+
* --capabilities " membership , x " → ["membership","x"] (trimmed)
|
|
91
|
+
* --capabilities "" → [] (revoke all;
|
|
92
|
+
* server stores empty as null)
|
|
93
|
+
*
|
|
94
|
+
* The set of grantable capability names ("membership" / "secrets") is validated
|
|
95
|
+
* server-side by `validateWorkflowIdentityConfig`; the CLI intentionally does
|
|
96
|
+
* NOT duplicate that allowlist so it can't drift from the server. An unknown
|
|
97
|
+
* name is surfaced via the server's structured `details[]` error.
|
|
98
|
+
*
|
|
99
|
+
* The caller applies presence-guarded plumbing (`options.capabilities !==
|
|
100
|
+
* undefined`) so an omitted flag never reaches the payload — the server's
|
|
101
|
+
* `hasOwnProperty` guard then leaves the existing grant untouched.
|
|
102
|
+
*/
|
|
103
|
+
export function parseCapabilitiesFlag(value) {
|
|
104
|
+
return value
|
|
105
|
+
.split(",")
|
|
106
|
+
.map((cap) => cap.trim())
|
|
107
|
+
.filter((cap) => cap.length > 0);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Fork 2 (#1249): a TOML pushed at a specific `<id>` may also declare a `key` /
|
|
111
|
+
* `workflowKey`. If it differs from the target's actual key, that's almost
|
|
112
|
+
* certainly the wrong file — error rather than silently ignoring it. An absent
|
|
113
|
+
* TOML key is advisory and allowed (the operation targets `<id>`).
|
|
114
|
+
*
|
|
115
|
+
* Returns an error message string when there is a mismatch, otherwise null.
|
|
116
|
+
* Pure function for unit testing.
|
|
117
|
+
*/
|
|
118
|
+
export function workflowKeyMismatchError(tomlWorkflow, existingWorkflowKey) {
|
|
119
|
+
const tomlKey = tomlWorkflow?.key ?? tomlWorkflow?.workflowKey;
|
|
120
|
+
if (tomlKey && existingWorkflowKey && tomlKey !== existingWorkflowKey) {
|
|
121
|
+
return (`TOML workflow key "${tomlKey}" does not match the target workflow's key ` +
|
|
122
|
+
`"${existingWorkflowKey}". This usually means you pointed --from-file at the ` +
|
|
123
|
+
`wrong workflow id. Remove the key from the TOML or target the matching id.`);
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=workflow-apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-apply.js","sourceRoot":"","sources":["../../../src/lib/workflow-apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,4BAA4B,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpF,+EAA+E;AAC/E,6EAA6E;AAC7E,6EAA6E;AAC7E,OAAO,EAAE,aAAa,EAAE,CAAC;AAwBzB;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAiB,EACjB,KAAa,EACb,UAAkB,EAClB,QAAa,EACb,KAAY,EACZ,OAAiC,EAAE;IAEnC,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAE3D,6EAA6E;IAC7E,+EAA+E;IAC/E,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,+EAA+E;IAC/E,0DAA0D;IAC1D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAc,CACzC,KAAK,EACL,UAAU,EACV;QACE,GAAG,4BAA4B,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC7D,0EAA0E;QAC1E,oEAAoE;QACpE,uEAAuE;QACvE,oEAAoE;QACpE,gEAAgE;QAChE,gBAAgB,EACd,QAAQ,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS;KAClF,EACD,kBAAkB,CACnB,CAAC;IAEF,4EAA4E;IAC5E,4EAA4E;IAC5E,gBAAgB;IAChB,IAAI,gBAAgB,GAAuB,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC;IAEzE,qEAAqE;IACrE,IAAI,eAAe,GAAG,eAAe,CAAC;IACtC,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,CAAC,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE;YAClD,KAAK;YACL,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;SAC/E,CAAC,CAAC;QACH,eAAe,GAAG,gBAAgB,CAAC;IACrC,CAAC;IAED,+EAA+E;IAC/E,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAI,QAAQ,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,mBAAmB,GAAG,MAAM,MAAM,CAAC,cAAc,CACrD,KAAK,EACL,UAAU,EACV,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,EACvC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CACrC,CAAC;QACF,IAAI,mBAAmB,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;YAC9C,gBAAgB,GAAG,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACjE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CACtC,YAAiB,EACjB,mBAAuC;IAEvC,MAAM,OAAO,GAAG,YAAY,EAAE,GAAG,IAAI,YAAY,EAAE,WAAW,CAAC;IAC/D,IAAI,OAAO,IAAI,mBAAmB,IAAI,OAAO,KAAK,mBAAmB,EAAE,CAAC;QACtE,OAAO,CACL,sBAAsB,OAAO,6CAA6C;YAC1E,IAAI,mBAAmB,uDAAuD;YAC9E,4EAA4E,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|