primitive-admin 1.2.0-alpha.3 → 1.2.0-alpha.5
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/assets/skill/skills/primitive-platform/SKILL.md +17 -0
- package/dist/src/commands/agent-sessions.js +4 -0
- package/dist/src/commands/agent-sessions.js.map +1 -1
- package/dist/src/commands/auth.js +7 -4
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/connections.js +11 -12
- package/dist/src/commands/connections.js.map +1 -1
- package/dist/src/commands/database-type-configs.js +2 -76
- package/dist/src/commands/database-type-configs.js.map +1 -1
- package/dist/src/commands/database-types.js +313 -13
- package/dist/src/commands/database-types.js.map +1 -1
- package/dist/src/commands/databases.d.ts +9 -0
- package/dist/src/commands/databases.js +78 -403
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.d.ts +32 -2
- package/dist/src/commands/documents.js +344 -711
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/functions.js +2 -2
- package/dist/src/commands/functions.js.map +1 -1
- package/dist/src/commands/llm.js +6 -9
- package/dist/src/commands/llm.js.map +1 -1
- package/dist/src/commands/prompts.d.ts +7 -0
- package/dist/src/commands/prompts.js +44 -0
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/settings.d.ts +9 -12
- package/dist/src/commands/settings.js +79 -31
- package/dist/src/commands/settings.js.map +1 -1
- package/dist/src/commands/sync.d.ts +43 -110
- package/dist/src/commands/sync.js +356 -1251
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/lib/aggregate-output.d.ts +25 -0
- package/dist/src/lib/aggregate-output.js +53 -0
- package/dist/src/lib/aggregate-output.js.map +1 -0
- package/dist/src/lib/api-client.d.ts +48 -204
- package/dist/src/lib/api-client.js +57 -321
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +6 -7
- package/dist/src/lib/codegen-shared/generatedFiles.js +2 -2
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
- package/dist/src/lib/codegen-shared/prettierStable.d.ts +1 -1
- package/dist/src/lib/codegen-shared/prettierStable.js +1 -1
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +2 -2
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +2 -2
- package/dist/src/lib/config-object-descriptor.js +15 -10
- package/dist/src/lib/config-object-descriptor.js.map +1 -1
- package/dist/src/lib/config-surface.d.ts +2 -1
- package/dist/src/lib/config-surface.js +4 -1
- package/dist/src/lib/config-surface.js.map +1 -1
- package/dist/src/lib/connections-list.d.ts +10 -0
- package/dist/src/lib/connections-list.js +18 -0
- package/dist/src/lib/connections-list.js.map +1 -0
- package/dist/src/lib/csv.d.ts +8 -9
- package/dist/src/lib/csv.js +3 -4
- package/dist/src/lib/csv.js.map +1 -1
- package/dist/src/lib/db-codegen/dbGenerator.js +5 -16
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/db-codegen/dbNaming.d.ts +5 -13
- package/dist/src/lib/db-codegen/dbNaming.js +5 -17
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +7 -56
- package/dist/src/lib/db-codegen/dbTemplates.js +25 -125
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTsTypes.d.ts +2 -2
- package/dist/src/lib/db-codegen/dbTsTypes.js +2 -2
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +60 -2
- package/dist/src/lib/db-codegen/dbTypeIR.js +12 -1
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -1
- package/dist/src/lib/document-export-record-log.d.ts +57 -0
- package/dist/src/lib/document-export-record-log.js +215 -0
- package/dist/src/lib/document-export-record-log.js.map +1 -0
- package/dist/src/lib/document-ingest-artifact.d.ts +13 -2
- package/dist/src/lib/document-ingest-artifact.js +7 -3
- package/dist/src/lib/document-ingest-artifact.js.map +1 -1
- package/dist/src/lib/document-ingest-rows.d.ts +16 -0
- package/dist/src/lib/document-ingest-rows.js +17 -0
- package/dist/src/lib/document-ingest-rows.js.map +1 -1
- package/dist/src/lib/document-ingest.d.ts +22 -0
- package/dist/src/lib/document-ingest.js +33 -0
- package/dist/src/lib/document-ingest.js.map +1 -1
- package/dist/src/lib/function-sync.d.ts +3 -16
- package/dist/src/lib/function-sync.js +14 -18
- package/dist/src/lib/function-sync.js.map +1 -1
- package/dist/src/lib/function-triggers.d.ts +3 -15
- package/dist/src/lib/function-triggers.js +10 -72
- package/dist/src/lib/function-triggers.js.map +1 -1
- package/dist/src/lib/generated-allowlist.js +0 -20
- package/dist/src/lib/generated-allowlist.js.map +1 -1
- package/dist/src/lib/generated-config-surfaces.d.ts +212 -49
- package/dist/src/lib/generated-config-surfaces.js +759 -184
- package/dist/src/lib/generated-config-surfaces.js.map +1 -1
- package/dist/src/lib/generated-sdk-types.d.ts +1 -1
- package/dist/src/lib/generated-sdk-types.js +1 -1
- package/dist/src/lib/generated-sdk-types.js.map +1 -1
- package/dist/src/lib/login-scope-lines.d.ts +15 -0
- package/dist/src/lib/login-scope-lines.js +22 -0
- package/dist/src/lib/login-scope-lines.js.map +1 -0
- package/dist/src/lib/paginate.d.ts +0 -5
- package/dist/src/lib/paginate.js +0 -5
- package/dist/src/lib/paginate.js.map +1 -1
- package/dist/src/lib/prompt-schema-codegen.js +5 -2
- package/dist/src/lib/prompt-schema-codegen.js.map +1 -1
- package/dist/src/lib/refresh-admin-credentials.d.ts +7 -0
- package/dist/src/lib/refresh-admin-credentials.js +16 -4
- package/dist/src/lib/refresh-admin-credentials.js.map +1 -1
- package/dist/src/lib/root-import-decision.d.ts +15 -14
- package/dist/src/lib/root-import-decision.js +44 -51
- package/dist/src/lib/root-import-decision.js.map +1 -1
- package/dist/src/lib/snapshot-build-rows.d.ts +21 -0
- package/dist/src/lib/snapshot-build-rows.js +22 -0
- package/dist/src/lib/snapshot-build-rows.js.map +1 -1
- package/dist/src/lib/snapshot-build.js +8 -3
- package/dist/src/lib/snapshot-build.js.map +1 -1
- package/dist/src/lib/swift-codegen/banners.d.ts +34 -7
- package/dist/src/lib/swift-codegen/banners.js +37 -7
- package/dist/src/lib/swift-codegen/banners.js.map +1 -1
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +4 -3
- package/dist/src/lib/swift-codegen/dbGenerator.js +14 -117
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/functionGenerator.d.ts +3 -3
- package/dist/src/lib/swift-codegen/functionGenerator.js +22 -17
- package/dist/src/lib/swift-codegen/functionGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/generator.d.ts +5 -5
- package/dist/src/lib/swift-codegen/generator.js +35 -40
- package/dist/src/lib/swift-codegen/generator.js.map +1 -1
- package/dist/src/lib/toml-database-config.d.ts +14 -75
- package/dist/src/lib/toml-database-config.js +14 -305
- package/dist/src/lib/toml-database-config.js.map +1 -1
- package/dist/src/lib/workflow-codegen/generator.d.ts +7 -7
- package/dist/src/lib/workflow-codegen/generator.js +16 -23
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +6 -12
- package/dist/src/lib/workflow-codegen/invokerIR.js +4 -5
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -1
- package/dist/src/lib/workflow-toml-validator.d.ts +2 -0
- package/dist/src/lib/workflow-toml-validator.js +28 -1
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/package.json +3 -5
- package/dist/src/lib/generated-workflow-model-fields.d.ts +0 -20
- package/dist/src/lib/generated-workflow-model-fields.js +0 -53
- package/dist/src/lib/generated-workflow-model-fields.js.map +0 -1
- package/dist/src/lib/workflow-field-descriptor.d.ts +0 -91
- package/dist/src/lib/workflow-field-descriptor.js +0 -153
- package/dist/src/lib/workflow-field-descriptor.js.map +0 -1
|
@@ -11,6 +11,15 @@ import { drainAppsUntilConverged, } from "./workflow-usage.js";
|
|
|
11
11
|
* fewest round trips the contract allows; a larger value is clamped there.
|
|
12
12
|
*/
|
|
13
13
|
const ADMIN_INVENTORY_PAGE_SIZE = 100;
|
|
14
|
+
/** The agent block's wire keys, in the surface's order. */
|
|
15
|
+
const AGENT_TEST_CASE_WIRE_KEYS = [
|
|
16
|
+
"agentHistory",
|
|
17
|
+
"agentContext",
|
|
18
|
+
"agentTimezone",
|
|
19
|
+
"agentLocale",
|
|
20
|
+
"agentExpectedToolCall",
|
|
21
|
+
"agentExpectedNoToolCall",
|
|
22
|
+
];
|
|
14
23
|
export class ApiError extends Error {
|
|
15
24
|
statusCode;
|
|
16
25
|
code;
|
|
@@ -125,55 +134,15 @@ export function parseErrorResponse(response, text, path) {
|
|
|
125
134
|
return { message, code, details, raw: errorData };
|
|
126
135
|
}
|
|
127
136
|
/**
|
|
128
|
-
* Typed exception
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* continue to work; specialized catch blocks can branch on `instanceof`.
|
|
132
|
-
*
|
|
133
|
-
* Per round-2 addendum A1, `details` is always preserved so callers can
|
|
134
|
-
* extract structured offender lists (refs[], operations[], etc.).
|
|
137
|
+
* Typed exception for the database-schema feature (issue #666): a stored
|
|
138
|
+
* schema that does not parse. `details` carries the line and column.
|
|
139
|
+
* (#3189 — the operation gates' exceptions retired with operations.)
|
|
135
140
|
*/
|
|
136
|
-
export class SchemaRequiredError extends ApiError {
|
|
137
|
-
constructor(message, details) {
|
|
138
|
-
super(message, 422, "SCHEMA_REQUIRED", details);
|
|
139
|
-
this.name = "SchemaRequiredError";
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
141
|
function detailsRecord(details) {
|
|
143
142
|
return details && !Array.isArray(details) && typeof details === "object"
|
|
144
143
|
? details
|
|
145
144
|
: undefined;
|
|
146
145
|
}
|
|
147
|
-
export class OperationRefError extends ApiError {
|
|
148
|
-
constructor(message, details) {
|
|
149
|
-
super(message, 422, "OPERATION_REFERENCES_UNDEFINED", details);
|
|
150
|
-
this.name = "OperationRefError";
|
|
151
|
-
}
|
|
152
|
-
get refs() {
|
|
153
|
-
const d = detailsRecord(this.details);
|
|
154
|
-
return Array.isArray(d?.refs) ? d.refs : [];
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
export class SchemaBreaksOpsError extends ApiError {
|
|
158
|
-
constructor(message, details) {
|
|
159
|
-
super(message, 422, "SCHEMA_BREAKS_OPERATIONS", details);
|
|
160
|
-
this.name = "SchemaBreaksOpsError";
|
|
161
|
-
}
|
|
162
|
-
get operations() {
|
|
163
|
-
const d = detailsRecord(this.details);
|
|
164
|
-
return Array.isArray(d?.operations) ? d.operations : [];
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
export class SchemaHasUncheckableOpsError extends ApiError {
|
|
168
|
-
constructor(message, details) {
|
|
169
|
-
super(message, 422, "SCHEMA_HAS_UNCHECKABLE_OPS", details);
|
|
170
|
-
this.name = "SchemaHasUncheckableOpsError";
|
|
171
|
-
}
|
|
172
|
-
get operations() {
|
|
173
|
-
const d = detailsRecord(this.details);
|
|
174
|
-
return Array.isArray(d?.operations) ? d.operations : [];
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
146
|
export class TomlParseError extends ApiError {
|
|
178
147
|
constructor(message, details) {
|
|
179
148
|
super(message, 400, "TOML_PARSE_ERROR", details);
|
|
@@ -188,55 +157,6 @@ export class TomlParseError extends ApiError {
|
|
|
188
157
|
return typeof d?.column === "number" ? d.column : undefined;
|
|
189
158
|
}
|
|
190
159
|
}
|
|
191
|
-
export class OpsExistError extends ApiError {
|
|
192
|
-
constructor(message, details) {
|
|
193
|
-
super(message, 409, "OPS_EXIST", details);
|
|
194
|
-
this.name = "OpsExistError";
|
|
195
|
-
}
|
|
196
|
-
get opCount() {
|
|
197
|
-
const d = detailsRecord(this.details);
|
|
198
|
-
return typeof d?.opCount === "number" ? d.opCount : 0;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Normalize a `databases operations execute` result to the CLI's one list
|
|
203
|
-
* envelope — but only when the result is a Durable Object query page
|
|
204
|
-
* (issue #2440).
|
|
205
|
-
*
|
|
206
|
-
* A registered operation is a list only sometimes. Of the shapes the server's
|
|
207
|
-
* operation dispatch can return, exactly two carry a top-level `data` array: a
|
|
208
|
-
* bare `query` and a `pipeline` whose `returnField` names a query step. A
|
|
209
|
-
* `count` (`{ count }`), an `aggregate` (`{ result }`), a mutation
|
|
210
|
-
* (`{ results }`), an `applyToQuery` (`{ matched, affected, failed, … }`) and a
|
|
211
|
-
* `returnField: "all"` pipeline (`{ steps: { … } }`) do not, so blanket
|
|
212
|
-
* normalization would corrupt them. This helper therefore tests the shape
|
|
213
|
-
* first and passes everything else through byte-for-byte — including the
|
|
214
|
-
* nested steps of a `returnField: "all"` pipeline, which are operation-defined
|
|
215
|
-
* objects the CLI must not reach into.
|
|
216
|
-
*
|
|
217
|
-
* Deliberately narrow, not a general-purpose predicate: the contract is
|
|
218
|
-
* specifically "an operations-execute result may be a DO query page".
|
|
219
|
-
* `executeDatabaseOperation()` is the only caller.
|
|
220
|
-
*
|
|
221
|
-
* The conversion itself is delegated to `normalizeCliListEnvelope()` so cursor
|
|
222
|
-
* handling, `prevCursor` dropping and `hasMore` derivation have exactly one
|
|
223
|
-
* implementation. That helper throws on an unrecognized shape — correct when
|
|
224
|
-
* the payload is supposed to be a list, wrong here, where the payload is the
|
|
225
|
-
* caller's own result — which is why the shape test has to run first. `_timing`
|
|
226
|
-
* (`--timing`) is re-attached afterwards, since it rides alongside the envelope
|
|
227
|
-
* rather than inside it.
|
|
228
|
-
*/
|
|
229
|
-
export function normalizeDatabaseOperationResult(raw) {
|
|
230
|
-
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
231
|
-
return raw;
|
|
232
|
-
const page = raw;
|
|
233
|
-
if (!Array.isArray(page.data))
|
|
234
|
-
return raw;
|
|
235
|
-
const envelope = normalizeCliListEnvelope(page);
|
|
236
|
-
if (page._timing !== undefined)
|
|
237
|
-
envelope._timing = page._timing;
|
|
238
|
-
return envelope;
|
|
239
|
-
}
|
|
240
160
|
export class ApiClient {
|
|
241
161
|
/**
|
|
242
162
|
* Loaded on first use (`ensureAuthenticated`), never in a constructor.
|
|
@@ -293,8 +213,9 @@ export class ApiClient {
|
|
|
293
213
|
// error or a server-side rejection. Callers that need a finer
|
|
294
214
|
// distinction (e.g. `primitive token`) consume RefreshError directly
|
|
295
215
|
// from refresh-admin-credentials.ts instead of going through here.
|
|
296
|
-
// A
|
|
297
|
-
|
|
216
|
+
// A refusal naming the session says why: revoked (#3885), or a login
|
|
217
|
+
// made before scoped sessions (#3891).
|
|
218
|
+
throw new ApiError(err.code === "SESSION_REVOKED" || err.code === "SESSION_UNSCOPED"
|
|
298
219
|
? err.message
|
|
299
220
|
: "Token refresh failed. Please login again.", 401, err.code);
|
|
300
221
|
}
|
|
@@ -383,24 +304,9 @@ export class ApiClient {
|
|
|
383
304
|
if (response.status === 409 && parsed.code === "CONFLICT") {
|
|
384
305
|
return new ConflictError(parsed.message, serverModifiedAt, expectedModifiedAt, detailsRecord);
|
|
385
306
|
}
|
|
386
|
-
if (response.status === 409 && parsed.code === "OPS_EXIST") {
|
|
387
|
-
return new OpsExistError(parsed.message, detailsRecord);
|
|
388
|
-
}
|
|
389
307
|
if (response.status === 400 && parsed.code === "TOML_PARSE_ERROR") {
|
|
390
308
|
return new TomlParseError(parsed.message, detailsRecord);
|
|
391
309
|
}
|
|
392
|
-
if (response.status === 422 && parsed.code === "SCHEMA_REQUIRED") {
|
|
393
|
-
return new SchemaRequiredError(parsed.message, detailsRecord);
|
|
394
|
-
}
|
|
395
|
-
if (response.status === 422 && parsed.code === "OPERATION_REFERENCES_UNDEFINED") {
|
|
396
|
-
return new OperationRefError(parsed.message, detailsRecord);
|
|
397
|
-
}
|
|
398
|
-
if (response.status === 422 && parsed.code === "SCHEMA_BREAKS_OPERATIONS") {
|
|
399
|
-
return new SchemaBreaksOpsError(parsed.message, detailsRecord);
|
|
400
|
-
}
|
|
401
|
-
if (response.status === 422 && parsed.code === "SCHEMA_HAS_UNCHECKABLE_OPS") {
|
|
402
|
-
return new SchemaHasUncheckableOpsError(parsed.message, detailsRecord);
|
|
403
|
-
}
|
|
404
310
|
return new ApiError(parsed.message, response.status, parsed.code, parsed.details);
|
|
405
311
|
}
|
|
406
312
|
/**
|
|
@@ -1140,10 +1046,9 @@ export class ApiClient {
|
|
|
1140
1046
|
// ============================================
|
|
1141
1047
|
/**
|
|
1142
1048
|
* List the live connections the server believes exist for exactly one of a
|
|
1143
|
-
* document
|
|
1049
|
+
* document or user. Read-only inspection over admin-api. Rows are
|
|
1144
1050
|
* per-connection-×-subscription bindings, so `connectionId` is not unique
|
|
1145
|
-
* across rows.
|
|
1146
|
-
* bound CEL input — typed `unknown`.
|
|
1051
|
+
* across rows.
|
|
1147
1052
|
*/
|
|
1148
1053
|
async listConnections(appId, selector, params) {
|
|
1149
1054
|
const result = await this.get(`/admin/api/apps/${appId}/connections`, {
|
|
@@ -1529,6 +1434,13 @@ export class ApiClient {
|
|
|
1529
1434
|
if (payload.expectedJsonSubset) {
|
|
1530
1435
|
serverPayload.expectedJsonSubset = payload.expectedJsonSubset;
|
|
1531
1436
|
}
|
|
1437
|
+
// #4262 — an agent case's `[test.agent]` keys, each when the caller set it:
|
|
1438
|
+
// presence, not truthiness, so `agentExpectedNoToolCall: false` travels. A
|
|
1439
|
+
// chat case sets none, and its body is unchanged.
|
|
1440
|
+
for (const key of AGENT_TEST_CASE_WIRE_KEYS) {
|
|
1441
|
+
if (payload[key] !== undefined)
|
|
1442
|
+
serverPayload[key] = payload[key];
|
|
1443
|
+
}
|
|
1532
1444
|
return this.post(`/admin/api/apps/${appId}/blocks/${blockType}/${blockId}/test-cases`, serverPayload);
|
|
1533
1445
|
}
|
|
1534
1446
|
async updateTestCase(appId, blockType, blockId, testCaseId, payload) {
|
|
@@ -1563,6 +1475,11 @@ export class ApiClient {
|
|
|
1563
1475
|
}
|
|
1564
1476
|
if (payload.key !== undefined)
|
|
1565
1477
|
serverPayload.key = payload.key;
|
|
1478
|
+
// #4262 — as on create; an explicit `null` clears the field.
|
|
1479
|
+
for (const key of AGENT_TEST_CASE_WIRE_KEYS) {
|
|
1480
|
+
if (payload[key] !== undefined)
|
|
1481
|
+
serverPayload[key] = payload[key];
|
|
1482
|
+
}
|
|
1566
1483
|
return this.patch(`/admin/api/apps/${appId}/blocks/${blockType}/${blockId}/test-cases/${testCaseId}`, serverPayload);
|
|
1567
1484
|
}
|
|
1568
1485
|
async deleteTestCase(appId, blockType, blockId, testCaseId) {
|
|
@@ -2126,72 +2043,6 @@ export class ApiClient {
|
|
|
2126
2043
|
});
|
|
2127
2044
|
}
|
|
2128
2045
|
// ============================================
|
|
2129
|
-
// DATABASE OPERATIONS (registered operations)
|
|
2130
|
-
// ============================================
|
|
2131
|
-
async listDatabaseOperations(appId, databaseId) {
|
|
2132
|
-
return this.get(`/app/${appId}/api/databases/${databaseId}/operations`);
|
|
2133
|
-
}
|
|
2134
|
-
/**
|
|
2135
|
-
* Execute a registered operation and, when the result is a query page,
|
|
2136
|
-
* normalize it to the CLI's one list envelope (issue #2440).
|
|
2137
|
-
*
|
|
2138
|
-
* The registered operation decides the response shape, so the normalization
|
|
2139
|
-
* is conditional — see {@link normalizeDatabaseOperationResult}. Everything
|
|
2140
|
-
* else (a `count`, an `aggregate`, a mutation, a `returnField: "all"`
|
|
2141
|
-
* pipeline) is returned exactly as the server sent it.
|
|
2142
|
-
*/
|
|
2143
|
-
async executeDatabaseOperation(appId, databaseId, operationName, data, token, options) {
|
|
2144
|
-
const path = `/app/${appId}/api/databases/${databaseId}/operations/${encodeURIComponent(operationName)}/execute`;
|
|
2145
|
-
const extraHeaders = {};
|
|
2146
|
-
if (options?.timing) {
|
|
2147
|
-
extraHeaders["X-Timing"] = "true";
|
|
2148
|
-
}
|
|
2149
|
-
if (token) {
|
|
2150
|
-
return normalizeDatabaseOperationResult(await this.requestWithToken(path, token, {
|
|
2151
|
-
method: "POST",
|
|
2152
|
-
body: JSON.stringify(data || {}),
|
|
2153
|
-
headers: extraHeaders,
|
|
2154
|
-
}));
|
|
2155
|
-
}
|
|
2156
|
-
return normalizeDatabaseOperationResult(await this.request(path, {
|
|
2157
|
-
method: "POST",
|
|
2158
|
-
body: JSON.stringify(data || {}),
|
|
2159
|
-
headers: extraHeaders,
|
|
2160
|
-
}));
|
|
2161
|
-
}
|
|
2162
|
-
/**
|
|
2163
|
-
* Execute a registered batch (bulk) database operation. Posts a chunk of
|
|
2164
|
-
* items to the canonical `operations/:name/batch` endpoint (the same one the
|
|
2165
|
-
* client library's `executeBatch` uses — NOT the deprecated `import-bulk`
|
|
2166
|
-
* alias). Used by `databases import-csv`.
|
|
2167
|
-
*
|
|
2168
|
-
* @returns `{ imported, failed }` — DO-level write outcome counts. Per-item
|
|
2169
|
-
* validation/access failures abort the whole chunk with a 4xx (thrown).
|
|
2170
|
-
*/
|
|
2171
|
-
async executeBatch(appId, databaseId, operationName, batch) {
|
|
2172
|
-
return this.post(`/app/${appId}/api/databases/${databaseId}/operations/${encodeURIComponent(operationName)}/batch`, { batch });
|
|
2173
|
-
}
|
|
2174
|
-
/**
|
|
2175
|
-
* Make a request using a specific JWT token instead of the CLI's credentials.
|
|
2176
|
-
* Used for executing operations as a different user.
|
|
2177
|
-
*/
|
|
2178
|
-
async requestWithToken(path, token, options = {}) {
|
|
2179
|
-
const credentials = await this.ensureAuthenticated();
|
|
2180
|
-
const url = `${credentials.serverUrl}${path}`;
|
|
2181
|
-
const headers = {
|
|
2182
|
-
Authorization: `Bearer ${token}`,
|
|
2183
|
-
"Content-Type": "application/json",
|
|
2184
|
-
...(options.headers || {}),
|
|
2185
|
-
};
|
|
2186
|
-
const response = await fetchWithTLS(url, { ...options, headers });
|
|
2187
|
-
const text = await response.text();
|
|
2188
|
-
if (!response.ok) {
|
|
2189
|
-
const parsed = parseErrorResponse(response, text, path);
|
|
2190
|
-
throw new ApiError(parsed.message, response.status, parsed.code, parsed.details);
|
|
2191
|
-
}
|
|
2192
|
-
return text ? JSON.parse(text) : null;
|
|
2193
|
-
}
|
|
2194
|
-
// ============================================
|
|
2195
2046
|
// DATABASE INDEXES
|
|
2196
2047
|
// ============================================
|
|
2197
2048
|
async listDatabaseIndexes(appId, databaseId, modelName) {
|
|
@@ -2224,7 +2075,7 @@ export class ApiClient {
|
|
|
2224
2075
|
// Issue #1336 (codex round-1 P2): `dryRun` runs every create-time
|
|
2225
2076
|
// validation (inline CEL rule lint, manifest shape, schema TOML parse)
|
|
2226
2077
|
// WITHOUT persisting, so a fresh-type `config push --dry-run` surfaces a
|
|
2227
|
-
// malformed
|
|
2078
|
+
// malformed rule or manifest the same way the real POST would.
|
|
2228
2079
|
options) {
|
|
2229
2080
|
const query = options?.dryRun ? "?dryRun=true" : "";
|
|
2230
2081
|
return this.post(`/app/${appId}/api/databases/types${query}`, data);
|
|
@@ -2245,105 +2096,14 @@ export class ApiClient {
|
|
|
2245
2096
|
return this.delete(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}${query}`);
|
|
2246
2097
|
}
|
|
2247
2098
|
/**
|
|
2248
|
-
* Issue #666 Phase 3: ask the server to scaffold a TOML schema from
|
|
2249
|
-
*
|
|
2099
|
+
* Issue #666 Phase 3: ask the server to scaffold a TOML schema from the
|
|
2100
|
+
* type's databases (the models each holds, and their fields). Read-only —
|
|
2101
|
+
* does NOT persist.
|
|
2250
2102
|
*/
|
|
2251
2103
|
async scaffoldDatabaseTypeSchema(appId, databaseType) {
|
|
2252
2104
|
return this.post(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/schema:scaffold`, {});
|
|
2253
2105
|
}
|
|
2254
2106
|
// ============================================
|
|
2255
|
-
// DATABASE TYPE OPERATIONS
|
|
2256
|
-
// ============================================
|
|
2257
|
-
async listDatabaseTypeOperations(appId, databaseType) {
|
|
2258
|
-
return this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations`);
|
|
2259
|
-
}
|
|
2260
|
-
async getDatabaseTypeOperation(appId, databaseType, name) {
|
|
2261
|
-
return this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations/${encodeURIComponent(name)}`);
|
|
2262
|
-
}
|
|
2263
|
-
async createDatabaseTypeOperation(appId, databaseType, data,
|
|
2264
|
-
// Issue #813 (1A): when `dryRun` is set the server runs the op-edit gate
|
|
2265
|
-
// without persisting — used by `config push --dry-run` to surface gate
|
|
2266
|
-
// failures the real push would hit. `schemaOverride` lets the gate run
|
|
2267
|
-
// against the schema the SAME push is about to land (so an op that depends
|
|
2268
|
-
// on a new field isn't falsely rejected against the stale stored schema).
|
|
2269
|
-
//
|
|
2270
|
-
// Issue #915 (defect a, follow-up): for a FRESH db-type the parent config
|
|
2271
|
-
// does not exist on the server yet, so the server's "access required"
|
|
2272
|
-
// check has no `defaultAccess` to fall back on. Thread the TOML-declared
|
|
2273
|
-
// type-level `defaultAccess` so an op that omits `access` (intending to
|
|
2274
|
-
// inherit it after the type is created) isn't falsely rejected during the
|
|
2275
|
-
// dry-run. Server only trusts this on the fresh-type dry-run path.
|
|
2276
|
-
options) {
|
|
2277
|
-
const query = options?.dryRun ? "?dryRun=true" : "";
|
|
2278
|
-
let body = data;
|
|
2279
|
-
if (options?.dryRun && options.schemaOverride !== undefined) {
|
|
2280
|
-
body = { ...body, schemaOverride: options.schemaOverride };
|
|
2281
|
-
}
|
|
2282
|
-
if (options?.dryRun && options.defaultAccess !== undefined) {
|
|
2283
|
-
body = { ...body, defaultAccess: options.defaultAccess };
|
|
2284
|
-
}
|
|
2285
|
-
if (options?.dryRun && options.metadataManifestOverride !== undefined) {
|
|
2286
|
-
body = { ...body, metadataManifestOverride: options.metadataManifestOverride };
|
|
2287
|
-
}
|
|
2288
|
-
return this.post(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations${query}`, body);
|
|
2289
|
-
}
|
|
2290
|
-
async updateDatabaseTypeOperation(appId, databaseType, name, data, expectedModifiedAt,
|
|
2291
|
-
// Issue #813 (1A): dry-run runs the op-edit gate without persisting.
|
|
2292
|
-
// `schemaOverride` gates against the schema the same push is landing.
|
|
2293
|
-
// Issue #1336: `metadataManifestOverride` gates the op-access lint against
|
|
2294
|
-
// the manifest the same push is landing (see `createDatabaseTypeOperation`).
|
|
2295
|
-
options) {
|
|
2296
|
-
let body = expectedModifiedAt ? { ...data, expectedModifiedAt } : { ...data };
|
|
2297
|
-
if (options?.dryRun && options.schemaOverride !== undefined) {
|
|
2298
|
-
body = { ...body, schemaOverride: options.schemaOverride };
|
|
2299
|
-
}
|
|
2300
|
-
if (options?.dryRun && options.metadataManifestOverride !== undefined) {
|
|
2301
|
-
body = { ...body, metadataManifestOverride: options.metadataManifestOverride };
|
|
2302
|
-
}
|
|
2303
|
-
const query = options?.dryRun ? "?dryRun=true" : "";
|
|
2304
|
-
return this.patch(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations/${encodeURIComponent(name)}${query}`, body);
|
|
2305
|
-
}
|
|
2306
|
-
async deleteDatabaseTypeOperation(appId, databaseType, name) {
|
|
2307
|
-
return this.delete(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations/${encodeURIComponent(name)}`);
|
|
2308
|
-
}
|
|
2309
|
-
// ============================================
|
|
2310
|
-
// DATABASE TYPE SUBSCRIPTIONS (#740 / #803)
|
|
2311
|
-
// ============================================
|
|
2312
|
-
//
|
|
2313
|
-
// Transparent passthroughs against the server's type-scoped subscription
|
|
2314
|
-
// routes (GET/POST/PUT/DELETE `/databases/types/:type/subscriptions[/:key]`).
|
|
2315
|
-
// The wire format is authoritative in the controller
|
|
2316
|
-
// (`database-type-subscriptions-controller.ts`): create requires
|
|
2317
|
-
// `subscriptionKey`, `displayName`, `modelName`, `filter` (CEL), `access`
|
|
2318
|
-
// (CEL); optional `description`, `select` (string[]), `emit`
|
|
2319
|
-
// (enter/update/leave subset), `params` (object, ≤5 entries), `status`.
|
|
2320
|
-
//
|
|
2321
|
-
// The list endpoint wraps results in `{ items: [...] }` (unlike operations,
|
|
2322
|
-
// which returns a bare array). We unwrap here so callers get an array,
|
|
2323
|
-
// matching `listDatabaseTypeOperations`.
|
|
2324
|
-
async listDatabaseTypeSubscriptions(appId, databaseType) {
|
|
2325
|
-
const result = await this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions`);
|
|
2326
|
-
if (Array.isArray(result))
|
|
2327
|
-
return result;
|
|
2328
|
-
return Array.isArray(result?.items) ? result.items : [];
|
|
2329
|
-
}
|
|
2330
|
-
async getDatabaseTypeSubscription(appId, databaseType, subscriptionKey) {
|
|
2331
|
-
return this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions/${encodeURIComponent(subscriptionKey)}`);
|
|
2332
|
-
}
|
|
2333
|
-
async createDatabaseTypeSubscription(appId, databaseType, data) {
|
|
2334
|
-
return this.post(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions`, data);
|
|
2335
|
-
}
|
|
2336
|
-
async updateDatabaseTypeSubscription(appId, databaseType, subscriptionKey, data,
|
|
2337
|
-
// #2731 B10 — optimistic concurrency, as the sibling operation update has
|
|
2338
|
-
// had. Omitted (by `--force`, and by every caller predating it) means the
|
|
2339
|
-
// write stays unconditional.
|
|
2340
|
-
expectedModifiedAt) {
|
|
2341
|
-
return this.put(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions/${encodeURIComponent(subscriptionKey)}`, expectedModifiedAt ? { ...data, expectedModifiedAt } : data);
|
|
2342
|
-
}
|
|
2343
|
-
async deleteDatabaseTypeSubscription(appId, databaseType, subscriptionKey) {
|
|
2344
|
-
return this.delete(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions/${encodeURIComponent(subscriptionKey)}`);
|
|
2345
|
-
}
|
|
2346
|
-
// ============================================
|
|
2347
2107
|
// GROUPS
|
|
2348
2108
|
// ============================================
|
|
2349
2109
|
async listGroups(appId, params) {
|
|
@@ -2661,51 +2421,6 @@ export class ApiClient {
|
|
|
2661
2421
|
async importDocumentState(appId, documentId, stateBase64) {
|
|
2662
2422
|
return this.post(`/app/${appId}/api/documents/${documentId}/import/state`, { state: stateBase64 });
|
|
2663
2423
|
}
|
|
2664
|
-
/**
|
|
2665
|
-
* Upload one artifact of a large document's import chain (#2816,
|
|
2666
|
-
* behavior 20).
|
|
2667
|
-
*
|
|
2668
|
-
* The bytes travel raw and unmodified: the manifest's digest is over the
|
|
2669
|
-
* STORED bytes, so re-encoding a chunk here would fail its own verification
|
|
2670
|
-
* on install. The query says which artifact it is — the server derives the
|
|
2671
|
-
* key from the document it belongs to, so nothing here composes one.
|
|
2672
|
-
*/
|
|
2673
|
-
async uploadDocumentChainArtifact(appId, documentId, query, body) {
|
|
2674
|
-
const credentials = await this.ensureAuthenticated();
|
|
2675
|
-
const search = new URLSearchParams();
|
|
2676
|
-
for (const [key, value] of Object.entries(query)) {
|
|
2677
|
-
search.set(key, String(value));
|
|
2678
|
-
}
|
|
2679
|
-
const url = `${credentials.serverUrl}/app/${appId}/api/documents/${documentId}` +
|
|
2680
|
-
`/import/chain/artifact?${search.toString()}`;
|
|
2681
|
-
const headers = {
|
|
2682
|
-
Authorization: `Bearer ${credentials.accessToken}`,
|
|
2683
|
-
"Content-Type": "application/octet-stream",
|
|
2684
|
-
};
|
|
2685
|
-
if (credentials.globalAdminAppId) {
|
|
2686
|
-
headers["X-Global-Admin-App-Id"] = credentials.globalAdminAppId;
|
|
2687
|
-
}
|
|
2688
|
-
const response = await fetchWithTLS(url, {
|
|
2689
|
-
method: "POST",
|
|
2690
|
-
headers,
|
|
2691
|
-
body: body,
|
|
2692
|
-
});
|
|
2693
|
-
if (!response.ok) {
|
|
2694
|
-
// #3403 — through the shared parser: reading `error` alone dropped the
|
|
2695
|
-
// envelope's `code` and `details`, so the refusal reached the operator
|
|
2696
|
-
// (and `primitive documents import`) with nothing to branch on.
|
|
2697
|
-
throw await blobFailure(response, "Failed to upload import artifact: ");
|
|
2698
|
-
}
|
|
2699
|
-
return await response.json().catch(() => ({}));
|
|
2700
|
-
}
|
|
2701
|
-
/** Start installing an uploaded chain (#2816, behavior 20). */
|
|
2702
|
-
async installDocumentChain(appId, documentId, plan) {
|
|
2703
|
-
return this.post(`/app/${appId}/api/documents/${documentId}/import/chain`, plan);
|
|
2704
|
-
}
|
|
2705
|
-
/** How far a document's chain install has got (#2816, behavior 20). */
|
|
2706
|
-
async getDocumentChainInstall(appId, documentId) {
|
|
2707
|
-
return this.get(`/app/${appId}/api/documents/${documentId}/import/chain`);
|
|
2708
|
-
}
|
|
2709
2424
|
async getDocument(appId, documentId) {
|
|
2710
2425
|
return this.get(`/app/${appId}/api/documents/${documentId}`);
|
|
2711
2426
|
}
|
|
@@ -2796,6 +2511,23 @@ export class ApiClient {
|
|
|
2796
2511
|
async getDocumentStats(appId, documentId) {
|
|
2797
2512
|
return this.get(`/app/${appId}/api/documents/${documentId}/stats`);
|
|
2798
2513
|
}
|
|
2514
|
+
/**
|
|
2515
|
+
* A record-log document's room (#4306): `GET documents/:id/room` →
|
|
2516
|
+
* `{ ok, appId, documentId, documentFormat, room }`, `room` null for a
|
|
2517
|
+
* format that has no record room. With `refused` (#4310), the answer also
|
|
2518
|
+
* carries a page of that bulk load's refused rows. App admins only.
|
|
2519
|
+
*/
|
|
2520
|
+
async getDocumentRoom(appId, documentId, query = {}) {
|
|
2521
|
+
const params = new URLSearchParams();
|
|
2522
|
+
if (query.refused !== undefined)
|
|
2523
|
+
params.set("refused", query.refused);
|
|
2524
|
+
if (query.limit !== undefined)
|
|
2525
|
+
params.set("limit", String(query.limit));
|
|
2526
|
+
if (query.cursor !== undefined)
|
|
2527
|
+
params.set("cursor", query.cursor);
|
|
2528
|
+
const search = params.toString();
|
|
2529
|
+
return this.get(`/app/${appId}/api/documents/${documentId}/room${search ? `?${search}` : ""}`);
|
|
2530
|
+
}
|
|
2799
2531
|
/**
|
|
2800
2532
|
* A large document's snapshot builds, newest first, one page (#3432).
|
|
2801
2533
|
* `GET documents/:id/snapshots` → `{ items, hasMore, nextCursor? }`.
|
|
@@ -2829,9 +2561,13 @@ export class ApiClient {
|
|
|
2829
2561
|
async getDocumentIngest(appId, documentId, sessionId) {
|
|
2830
2562
|
return this.get(`/app/${appId}/api/documents/${documentId}/ingest/${encodeURIComponent(sessionId)}`);
|
|
2831
2563
|
}
|
|
2832
|
-
/**
|
|
2833
|
-
|
|
2834
|
-
|
|
2564
|
+
/**
|
|
2565
|
+
* Open a bulk-load session on a large document (#3435, criterion 9). A
|
|
2566
|
+
* record-log (format 3) document's load takes `reserveEpoch`, `mode` and a
|
|
2567
|
+
* refresh's `models` (#4310); `{}` keeps every format's defaults.
|
|
2568
|
+
*/
|
|
2569
|
+
async createDocumentIngest(appId, documentId, options = {}) {
|
|
2570
|
+
return this.post(`/app/${appId}/api/documents/${documentId}/ingest`, options);
|
|
2835
2571
|
}
|
|
2836
2572
|
/**
|
|
2837
2573
|
* Upload one chunk of a bulk-load session's artifact (#3435).
|