@eide/foir-cli 0.24.0 → 0.25.1
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.js +38 -10
- package/dist/lib/config-helpers.d.ts +46 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1281,6 +1281,7 @@ import {
|
|
|
1281
1281
|
FieldSchema as ProtoFieldSchema,
|
|
1282
1282
|
SharingConfigSchema as ProtoSharingConfigSchema,
|
|
1283
1283
|
ModelConfigSchema as ProtoModelConfigSchema,
|
|
1284
|
+
LookupDefinitionSchema as ProtoLookupDefinitionSchema,
|
|
1284
1285
|
CreateModelRequestSchema,
|
|
1285
1286
|
GetModelRequestSchema,
|
|
1286
1287
|
GetModelByKeyRequestSchema,
|
|
@@ -1328,7 +1329,13 @@ function jsConfigToProto(c) {
|
|
|
1328
1329
|
naturalKeyField: c.naturalKeyField,
|
|
1329
1330
|
systemEntity: c.systemEntity ?? false,
|
|
1330
1331
|
deletable: c.deletable,
|
|
1331
|
-
editable: c.editable
|
|
1332
|
+
editable: c.editable,
|
|
1333
|
+
lookups: c.lookups ? c.lookups.map(
|
|
1334
|
+
(l) => create3(ProtoLookupDefinitionSchema, {
|
|
1335
|
+
keyBy: l.keyBy ?? [],
|
|
1336
|
+
name: l.name
|
|
1337
|
+
})
|
|
1338
|
+
) : []
|
|
1332
1339
|
});
|
|
1333
1340
|
}
|
|
1334
1341
|
function createModelsMethods(client) {
|
|
@@ -1383,7 +1390,8 @@ function createModelsMethods(client) {
|
|
|
1383
1390
|
config: params.config ? jsConfigToProto(params.config) : void 0,
|
|
1384
1391
|
changeDescription: params.changeDescription,
|
|
1385
1392
|
updatePushSnapshot: params.updatePushSnapshot ?? false,
|
|
1386
|
-
snapshotOnly: params.snapshotOnly ?? false
|
|
1393
|
+
snapshotOnly: params.snapshotOnly ?? false,
|
|
1394
|
+
allowLookupRebuild: params.allowLookupRebuild ?? false
|
|
1387
1395
|
})
|
|
1388
1396
|
);
|
|
1389
1397
|
return resp.model ?? null;
|
|
@@ -2748,7 +2756,8 @@ function createOperationsMethods(client) {
|
|
|
2748
2756
|
precondition: params.precondition,
|
|
2749
2757
|
configId: params.configId,
|
|
2750
2758
|
supportsAsync: params.supportsAsync,
|
|
2751
|
-
callbackTtlSeconds: params.callbackTtlSeconds
|
|
2759
|
+
callbackTtlSeconds: params.callbackTtlSeconds,
|
|
2760
|
+
capabilities: params.capabilities ?? []
|
|
2752
2761
|
})
|
|
2753
2762
|
);
|
|
2754
2763
|
return resp.operation ?? null;
|
|
@@ -2769,7 +2778,8 @@ function createOperationsMethods(client) {
|
|
|
2769
2778
|
precondition: params.precondition,
|
|
2770
2779
|
isActive: params.isActive,
|
|
2771
2780
|
supportsAsync: params.supportsAsync,
|
|
2772
|
-
callbackTtlSeconds: params.callbackTtlSeconds
|
|
2781
|
+
callbackTtlSeconds: params.callbackTtlSeconds,
|
|
2782
|
+
capabilities: params.capabilities
|
|
2773
2783
|
})
|
|
2774
2784
|
);
|
|
2775
2785
|
return resp.operation ?? null;
|
|
@@ -5063,7 +5073,15 @@ async function reconcileConfig(client, configId, manifest, options = {}) {
|
|
|
5063
5073
|
const operationBaseUrl = manifest.operationBaseUrl ?? "";
|
|
5064
5074
|
const modelConflicts = [];
|
|
5065
5075
|
const mappingConflicts = [];
|
|
5066
|
-
await reconcileModels(
|
|
5076
|
+
await reconcileModels(
|
|
5077
|
+
client,
|
|
5078
|
+
configId,
|
|
5079
|
+
manifest.models ?? [],
|
|
5080
|
+
summary,
|
|
5081
|
+
options.force ?? false,
|
|
5082
|
+
options.allowLookupRebuild ?? false,
|
|
5083
|
+
modelConflicts
|
|
5084
|
+
);
|
|
5067
5085
|
await reconcileOperations(client, configId, manifest.operations ?? [], operationBaseUrl, summary);
|
|
5068
5086
|
await reconcileHooks(client, configId, manifest.hooks ?? [], summary);
|
|
5069
5087
|
await reconcileSegments(client, configId, manifest.segments ?? [], summary);
|
|
@@ -5094,7 +5112,7 @@ async function reconcileConfig(client, configId, manifest, options = {}) {
|
|
|
5094
5112
|
}
|
|
5095
5113
|
return summary;
|
|
5096
5114
|
}
|
|
5097
|
-
async function reconcileModels(client, configId, models, summary, force, conflictOut) {
|
|
5115
|
+
async function reconcileModels(client, configId, models, summary, force, allowLookupRebuild, conflictOut) {
|
|
5098
5116
|
const existing = await client.models.listModels({ limit: 200 });
|
|
5099
5117
|
const allByKey = new Map(
|
|
5100
5118
|
existing.items.map((m) => [m.key, m])
|
|
@@ -5111,6 +5129,7 @@ async function reconcileModels(client, configId, models, summary, force, conflic
|
|
|
5111
5129
|
if (m.pluralName) config2.pluralName = m.pluralName;
|
|
5112
5130
|
if (m.pluralKey) config2.pluralKey = m.pluralKey;
|
|
5113
5131
|
if (m.description) config2.description = m.description;
|
|
5132
|
+
if (m.lookups !== void 0) config2.lookups = m.lookups;
|
|
5114
5133
|
const ex = allByKey.get(m.key);
|
|
5115
5134
|
if (!ex) {
|
|
5116
5135
|
plans.push({ kind: "create", model: m, config: config2 });
|
|
@@ -5179,7 +5198,8 @@ async function reconcileModels(client, configId, models, summary, force, conflic
|
|
|
5179
5198
|
name: p.name,
|
|
5180
5199
|
fields: fieldsToWrite,
|
|
5181
5200
|
config: p.config,
|
|
5182
|
-
updatePushSnapshot: true
|
|
5201
|
+
updatePushSnapshot: true,
|
|
5202
|
+
allowLookupRebuild
|
|
5183
5203
|
});
|
|
5184
5204
|
summary.models.updated++;
|
|
5185
5205
|
summary.updatedModelIds.push(p.id);
|
|
@@ -5219,6 +5239,7 @@ async function reconcileOperations(client, configId, operations, operationBaseUr
|
|
|
5219
5239
|
`\u26A0 operation "${op.key}": mode=async but timeoutMs=${op.timeoutMs} \u2014 ack should return in <10s; long timeouts mask slow extensions`
|
|
5220
5240
|
);
|
|
5221
5241
|
}
|
|
5242
|
+
const capabilities = op.capabilities ?? [];
|
|
5222
5243
|
if (ex) {
|
|
5223
5244
|
const empty = {};
|
|
5224
5245
|
await client.operations.updateOperation({
|
|
@@ -5235,7 +5256,8 @@ async function reconcileOperations(client, configId, operations, operationBaseUr
|
|
|
5235
5256
|
precondition: op.precondition ?? empty,
|
|
5236
5257
|
isActive: op.isActive,
|
|
5237
5258
|
supportsAsync,
|
|
5238
|
-
callbackTtlSeconds: op.callbackTtlSeconds
|
|
5259
|
+
callbackTtlSeconds: op.callbackTtlSeconds,
|
|
5260
|
+
capabilities
|
|
5239
5261
|
});
|
|
5240
5262
|
summary.operations.updated++;
|
|
5241
5263
|
summary.updatedOperationIds.push(ex.id);
|
|
@@ -5257,7 +5279,8 @@ async function reconcileOperations(client, configId, operations, operationBaseUr
|
|
|
5257
5279
|
precondition: op.precondition,
|
|
5258
5280
|
configId,
|
|
5259
5281
|
supportsAsync,
|
|
5260
|
-
callbackTtlSeconds: op.callbackTtlSeconds
|
|
5282
|
+
callbackTtlSeconds: op.callbackTtlSeconds,
|
|
5283
|
+
capabilities
|
|
5261
5284
|
});
|
|
5262
5285
|
summary.operations.created++;
|
|
5263
5286
|
}
|
|
@@ -5802,6 +5825,10 @@ function registerPushCommand(program2, globalOpts) {
|
|
|
5802
5825
|
"--publish",
|
|
5803
5826
|
"Promote updated models, operations, auth providers, profile schema, and design tokens to the published channel after the push. New resources auto-publish; this flag covers updates, which are otherwise left as drafts.",
|
|
5804
5827
|
false
|
|
5828
|
+
).option(
|
|
5829
|
+
"--rebuild",
|
|
5830
|
+
"Accept lookup renames. A lookup with the same keyBy and a changed `name` override rebuilds its projection rows (old rows are dropped, new rows are re-emitted from records). Without this flag, the server rejects renames with a pointer here. Pure add / remove on lookups does not require this flag.",
|
|
5831
|
+
false
|
|
5805
5832
|
).option("--env <path>", "Path to .env file (default: .env)").action(
|
|
5806
5833
|
withErrorHandler(
|
|
5807
5834
|
globalOpts,
|
|
@@ -5862,7 +5889,8 @@ function registerPushCommand(program2, globalOpts) {
|
|
|
5862
5889
|
tenantId: resolved?.project.tenantId,
|
|
5863
5890
|
projectId: resolved?.project.id,
|
|
5864
5891
|
force: opts.force ?? false,
|
|
5865
|
-
publishDesignTokens: opts.publish ?? false
|
|
5892
|
+
publishDesignTokens: opts.publish ?? false,
|
|
5893
|
+
allowLookupRebuild: opts.rebuild ?? false
|
|
5866
5894
|
});
|
|
5867
5895
|
} catch (e) {
|
|
5868
5896
|
if (e instanceof PushConflictError) {
|
|
@@ -67,6 +67,23 @@ type GenericFieldDefinitionInput = BaseFieldDefinitionInput & {
|
|
|
67
67
|
};
|
|
68
68
|
};
|
|
69
69
|
type FieldDefinitionInput = SelectFieldDefinitionInput | EnumFieldDefinitionInput | GenericFieldDefinitionInput;
|
|
70
|
+
/**
|
|
71
|
+
* Lookup definition — declares one indexed access path on a model.
|
|
72
|
+
*
|
|
73
|
+
* `keyBy` is the ordered list of top-level scalar field keys that make
|
|
74
|
+
* up the lookup key. Single-field lookups are common; composites are
|
|
75
|
+
* first-class (e.g. `['fromHost', 'fromPath']` for a redirect model).
|
|
76
|
+
* `name` overrides the generated GraphQL query field name; omit it to
|
|
77
|
+
* use `<typeLowerCamel>By<PascalCaseKeyFields>`.
|
|
78
|
+
*
|
|
79
|
+
* Validation runs server-side via the platform's config-write RPC —
|
|
80
|
+
* see RFC §Data model → Constraints. The CLI does no local validation
|
|
81
|
+
* here; the server's structured error surfaces verbatim on failure.
|
|
82
|
+
*/
|
|
83
|
+
interface LookupDefinitionInput {
|
|
84
|
+
keyBy: string[];
|
|
85
|
+
name?: string;
|
|
86
|
+
}
|
|
70
87
|
interface ApplyConfigModelInput {
|
|
71
88
|
key: string;
|
|
72
89
|
name: string;
|
|
@@ -75,6 +92,12 @@ interface ApplyConfigModelInput {
|
|
|
75
92
|
description?: string;
|
|
76
93
|
fields?: FieldDefinitionInput[];
|
|
77
94
|
config?: Record<string, unknown>;
|
|
95
|
+
/**
|
|
96
|
+
* Lookup definitions for this model. Server validates: existence /
|
|
97
|
+
* scalar-type / top-level-only / caps (4 lookups, 4 fields) / GraphQL
|
|
98
|
+
* field-name regex for `name`. See RFC §Data model (config surface).
|
|
99
|
+
*/
|
|
100
|
+
lookups?: LookupDefinitionInput[];
|
|
78
101
|
}
|
|
79
102
|
interface QuotaRule {
|
|
80
103
|
/** Segment key to target (empty string or omitted = default/fallback). */
|
|
@@ -168,6 +191,28 @@ interface ApplyConfigOperationInput {
|
|
|
168
191
|
callbackTimeoutRetryPolicy?: {
|
|
169
192
|
maxRetries?: number;
|
|
170
193
|
};
|
|
194
|
+
/**
|
|
195
|
+
* Capability strings stamped onto the scoped dispatch token (and its
|
|
196
|
+
* callback-window successor) so the extension can call back into
|
|
197
|
+
* api-public with the precise authorities it needs — nothing more.
|
|
198
|
+
*
|
|
199
|
+
* Per-model record access is three-part: `records:read:<model_key>`,
|
|
200
|
+
* `records:write:<model_key>`, `records:delete:<model_key>`,
|
|
201
|
+
* `records:publish:<model_key>`. List every model the operation
|
|
202
|
+
* touches; the unscoped two-part forms (`records:read` etc.) only
|
|
203
|
+
* work for admin API keys and won't satisfy customer-scoped tokens.
|
|
204
|
+
*
|
|
205
|
+
* Cross-cutting caps: `embeddings:read`, `embeddings:write`,
|
|
206
|
+
* `shares:read`, `shares:write`, `files:read`, `files:write`,
|
|
207
|
+
* `config:read`, `status:write`, and the secrets:* family. See
|
|
208
|
+
* `services/internal/scopedtoken/capabilities.go` for the full enum.
|
|
209
|
+
*
|
|
210
|
+
* `operations:complete` is auto-injected on callback tokens — never
|
|
211
|
+
* declare it here. Omitting `capabilities` (or passing an empty array)
|
|
212
|
+
* mints an authentic-but-unprivileged token; useful for operations
|
|
213
|
+
* whose extension makes no back-channel calls.
|
|
214
|
+
*/
|
|
215
|
+
capabilities?: string[];
|
|
171
216
|
}
|
|
172
217
|
interface ApplyConfigSegmentInput {
|
|
173
218
|
key: string;
|
|
@@ -453,4 +498,4 @@ interface FoirSecretsConfig {
|
|
|
453
498
|
*/
|
|
454
499
|
declare function defineSecrets(config: FoirSecretsConfig): FoirSecretsConfig;
|
|
455
500
|
|
|
456
|
-
export { type AppInput, type AppPlacementFieldChoiceInput, type AppSinkMappingInput, type AppSourceMappingInput, type ApplyConfigApiKeyInput, type ApplyConfigAuthProviderInput, type ApplyConfigDesignTokensInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigProjectInput, type ApplyConfigProjectSettingsInput, type ApplyConfigScheduleInput, type ApplyConfigSegmentInput, type EnumFieldConfig, type EnumFieldDefinitionInput, type EnumFieldOption, type ExpressionPrecondition, type FieldDefinitionInput, type FoirSecretsConfig, type Precondition, type QuotaRule, type SecretDeclaration, type SecretOwnerKind, type SegmentPrecondition, type SelectFieldConfig, type SelectFieldDefinitionInput, defineAuthProvider, defineConfig, defineDesignTokens, defineEnumField, defineField, defineHook, defineModel, defineOperation, definePlacement, defineSchedule, defineSecrets, defineSegment, defineSelectField };
|
|
501
|
+
export { type AppInput, type AppPlacementFieldChoiceInput, type AppSinkMappingInput, type AppSourceMappingInput, type ApplyConfigApiKeyInput, type ApplyConfigAuthProviderInput, type ApplyConfigDesignTokensInput, type ApplyConfigHookInput, type ApplyConfigInput, type ApplyConfigModelInput, type ApplyConfigOperationInput, type ApplyConfigPlacementInput, type ApplyConfigProjectInput, type ApplyConfigProjectSettingsInput, type ApplyConfigScheduleInput, type ApplyConfigSegmentInput, type EnumFieldConfig, type EnumFieldDefinitionInput, type EnumFieldOption, type ExpressionPrecondition, type FieldDefinitionInput, type FoirSecretsConfig, type LookupDefinitionInput, type Precondition, type QuotaRule, type SecretDeclaration, type SecretOwnerKind, type SegmentPrecondition, type SelectFieldConfig, type SelectFieldDefinitionInput, defineAuthProvider, defineConfig, defineDesignTokens, defineEnumField, defineField, defineHook, defineModel, defineOperation, definePlacement, defineSchedule, defineSecrets, defineSegment, defineSelectField };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eide/foir-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "Universal platform CLI for Foir platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@bufbuild/protovalidate": "^1.1.1",
|
|
51
51
|
"@connectrpc/connect": "^2.0.0",
|
|
52
52
|
"@connectrpc/connect-node": "^2.0.0",
|
|
53
|
-
"@eide/foir-proto-ts": "^0.
|
|
53
|
+
"@eide/foir-proto-ts": "^0.66.0",
|
|
54
54
|
"chalk": "^5.3.0",
|
|
55
55
|
"commander": "^12.1.0",
|
|
56
56
|
"dotenv": "^16.4.5",
|