primitive-admin 1.2.0-alpha.4 → 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/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 +67 -367
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.d.ts +32 -2
- package/dist/src/commands/documents.js +281 -685
- 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/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 +31 -81
- package/dist/src/commands/sync.js +228 -1113
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +30 -199
- package/dist/src/lib/api-client.js +31 -297
- 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 +1 -5
- 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/dbNaming.d.ts +2 -1
- package/dist/src/lib/db-codegen/dbNaming.js +2 -1
- package/dist/src/lib/db-codegen/dbNaming.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 +59 -1
- 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-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 +40 -2
- package/dist/src/lib/generated-config-surfaces.js +160 -94
- 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/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/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.js +27 -27
- 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-toml-validator.js +15 -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
|
@@ -134,55 +134,15 @@ export function parseErrorResponse(response, text, path) {
|
|
|
134
134
|
return { message, code, details, raw: errorData };
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
|
-
* Typed exception
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* continue to work; specialized catch blocks can branch on `instanceof`.
|
|
141
|
-
*
|
|
142
|
-
* Per round-2 addendum A1, `details` is always preserved so callers can
|
|
143
|
-
* 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.)
|
|
144
140
|
*/
|
|
145
|
-
export class SchemaRequiredError extends ApiError {
|
|
146
|
-
constructor(message, details) {
|
|
147
|
-
super(message, 422, "SCHEMA_REQUIRED", details);
|
|
148
|
-
this.name = "SchemaRequiredError";
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
141
|
function detailsRecord(details) {
|
|
152
142
|
return details && !Array.isArray(details) && typeof details === "object"
|
|
153
143
|
? details
|
|
154
144
|
: undefined;
|
|
155
145
|
}
|
|
156
|
-
export class OperationRefError extends ApiError {
|
|
157
|
-
constructor(message, details) {
|
|
158
|
-
super(message, 422, "OPERATION_REFERENCES_UNDEFINED", details);
|
|
159
|
-
this.name = "OperationRefError";
|
|
160
|
-
}
|
|
161
|
-
get refs() {
|
|
162
|
-
const d = detailsRecord(this.details);
|
|
163
|
-
return Array.isArray(d?.refs) ? d.refs : [];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
export class SchemaBreaksOpsError extends ApiError {
|
|
167
|
-
constructor(message, details) {
|
|
168
|
-
super(message, 422, "SCHEMA_BREAKS_OPERATIONS", details);
|
|
169
|
-
this.name = "SchemaBreaksOpsError";
|
|
170
|
-
}
|
|
171
|
-
get operations() {
|
|
172
|
-
const d = detailsRecord(this.details);
|
|
173
|
-
return Array.isArray(d?.operations) ? d.operations : [];
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
export class SchemaHasUncheckableOpsError extends ApiError {
|
|
177
|
-
constructor(message, details) {
|
|
178
|
-
super(message, 422, "SCHEMA_HAS_UNCHECKABLE_OPS", details);
|
|
179
|
-
this.name = "SchemaHasUncheckableOpsError";
|
|
180
|
-
}
|
|
181
|
-
get operations() {
|
|
182
|
-
const d = detailsRecord(this.details);
|
|
183
|
-
return Array.isArray(d?.operations) ? d.operations : [];
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
146
|
export class TomlParseError extends ApiError {
|
|
187
147
|
constructor(message, details) {
|
|
188
148
|
super(message, 400, "TOML_PARSE_ERROR", details);
|
|
@@ -197,55 +157,6 @@ export class TomlParseError extends ApiError {
|
|
|
197
157
|
return typeof d?.column === "number" ? d.column : undefined;
|
|
198
158
|
}
|
|
199
159
|
}
|
|
200
|
-
export class OpsExistError extends ApiError {
|
|
201
|
-
constructor(message, details) {
|
|
202
|
-
super(message, 409, "OPS_EXIST", details);
|
|
203
|
-
this.name = "OpsExistError";
|
|
204
|
-
}
|
|
205
|
-
get opCount() {
|
|
206
|
-
const d = detailsRecord(this.details);
|
|
207
|
-
return typeof d?.opCount === "number" ? d.opCount : 0;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Normalize a `databases operations execute` result to the CLI's one list
|
|
212
|
-
* envelope — but only when the result is a Durable Object query page
|
|
213
|
-
* (issue #2440).
|
|
214
|
-
*
|
|
215
|
-
* A registered operation is a list only sometimes. Of the shapes the server's
|
|
216
|
-
* operation dispatch can return, exactly two carry a top-level `data` array: a
|
|
217
|
-
* bare `query` and a `pipeline` whose `returnField` names a query step. A
|
|
218
|
-
* `count` (`{ count }`), an `aggregate` (`{ result }`), a mutation
|
|
219
|
-
* (`{ results }`), an `applyToQuery` (`{ matched, affected, failed, … }`) and a
|
|
220
|
-
* `returnField: "all"` pipeline (`{ steps: { … } }`) do not, so blanket
|
|
221
|
-
* normalization would corrupt them. This helper therefore tests the shape
|
|
222
|
-
* first and passes everything else through byte-for-byte — including the
|
|
223
|
-
* nested steps of a `returnField: "all"` pipeline, which are operation-defined
|
|
224
|
-
* objects the CLI must not reach into.
|
|
225
|
-
*
|
|
226
|
-
* Deliberately narrow, not a general-purpose predicate: the contract is
|
|
227
|
-
* specifically "an operations-execute result may be a DO query page".
|
|
228
|
-
* `executeDatabaseOperation()` is the only caller.
|
|
229
|
-
*
|
|
230
|
-
* The conversion itself is delegated to `normalizeCliListEnvelope()` so cursor
|
|
231
|
-
* handling, `prevCursor` dropping and `hasMore` derivation have exactly one
|
|
232
|
-
* implementation. That helper throws on an unrecognized shape — correct when
|
|
233
|
-
* the payload is supposed to be a list, wrong here, where the payload is the
|
|
234
|
-
* caller's own result — which is why the shape test has to run first. `_timing`
|
|
235
|
-
* (`--timing`) is re-attached afterwards, since it rides alongside the envelope
|
|
236
|
-
* rather than inside it.
|
|
237
|
-
*/
|
|
238
|
-
export function normalizeDatabaseOperationResult(raw) {
|
|
239
|
-
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
240
|
-
return raw;
|
|
241
|
-
const page = raw;
|
|
242
|
-
if (!Array.isArray(page.data))
|
|
243
|
-
return raw;
|
|
244
|
-
const envelope = normalizeCliListEnvelope(page);
|
|
245
|
-
if (page._timing !== undefined)
|
|
246
|
-
envelope._timing = page._timing;
|
|
247
|
-
return envelope;
|
|
248
|
-
}
|
|
249
160
|
export class ApiClient {
|
|
250
161
|
/**
|
|
251
162
|
* Loaded on first use (`ensureAuthenticated`), never in a constructor.
|
|
@@ -302,8 +213,9 @@ export class ApiClient {
|
|
|
302
213
|
// error or a server-side rejection. Callers that need a finer
|
|
303
214
|
// distinction (e.g. `primitive token`) consume RefreshError directly
|
|
304
215
|
// from refresh-admin-credentials.ts instead of going through here.
|
|
305
|
-
// A
|
|
306
|
-
|
|
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"
|
|
307
219
|
? err.message
|
|
308
220
|
: "Token refresh failed. Please login again.", 401, err.code);
|
|
309
221
|
}
|
|
@@ -392,24 +304,9 @@ export class ApiClient {
|
|
|
392
304
|
if (response.status === 409 && parsed.code === "CONFLICT") {
|
|
393
305
|
return new ConflictError(parsed.message, serverModifiedAt, expectedModifiedAt, detailsRecord);
|
|
394
306
|
}
|
|
395
|
-
if (response.status === 409 && parsed.code === "OPS_EXIST") {
|
|
396
|
-
return new OpsExistError(parsed.message, detailsRecord);
|
|
397
|
-
}
|
|
398
307
|
if (response.status === 400 && parsed.code === "TOML_PARSE_ERROR") {
|
|
399
308
|
return new TomlParseError(parsed.message, detailsRecord);
|
|
400
309
|
}
|
|
401
|
-
if (response.status === 422 && parsed.code === "SCHEMA_REQUIRED") {
|
|
402
|
-
return new SchemaRequiredError(parsed.message, detailsRecord);
|
|
403
|
-
}
|
|
404
|
-
if (response.status === 422 && parsed.code === "OPERATION_REFERENCES_UNDEFINED") {
|
|
405
|
-
return new OperationRefError(parsed.message, detailsRecord);
|
|
406
|
-
}
|
|
407
|
-
if (response.status === 422 && parsed.code === "SCHEMA_BREAKS_OPERATIONS") {
|
|
408
|
-
return new SchemaBreaksOpsError(parsed.message, detailsRecord);
|
|
409
|
-
}
|
|
410
|
-
if (response.status === 422 && parsed.code === "SCHEMA_HAS_UNCHECKABLE_OPS") {
|
|
411
|
-
return new SchemaHasUncheckableOpsError(parsed.message, detailsRecord);
|
|
412
|
-
}
|
|
413
310
|
return new ApiError(parsed.message, response.status, parsed.code, parsed.details);
|
|
414
311
|
}
|
|
415
312
|
/**
|
|
@@ -1149,10 +1046,9 @@ export class ApiClient {
|
|
|
1149
1046
|
// ============================================
|
|
1150
1047
|
/**
|
|
1151
1048
|
* List the live connections the server believes exist for exactly one of a
|
|
1152
|
-
* document
|
|
1049
|
+
* document or user. Read-only inspection over admin-api. Rows are
|
|
1153
1050
|
* per-connection-×-subscription bindings, so `connectionId` is not unique
|
|
1154
|
-
* across rows.
|
|
1155
|
-
* bound CEL input — typed `unknown`.
|
|
1051
|
+
* across rows.
|
|
1156
1052
|
*/
|
|
1157
1053
|
async listConnections(appId, selector, params) {
|
|
1158
1054
|
const result = await this.get(`/admin/api/apps/${appId}/connections`, {
|
|
@@ -2147,45 +2043,6 @@ export class ApiClient {
|
|
|
2147
2043
|
});
|
|
2148
2044
|
}
|
|
2149
2045
|
// ============================================
|
|
2150
|
-
// DATABASE OPERATIONS (registered operations)
|
|
2151
|
-
// ============================================
|
|
2152
|
-
async listDatabaseOperations(appId, databaseId) {
|
|
2153
|
-
return this.get(`/app/${appId}/api/databases/${databaseId}/operations`);
|
|
2154
|
-
}
|
|
2155
|
-
/**
|
|
2156
|
-
* Execute a registered operation and, when the result is a query page,
|
|
2157
|
-
* normalize it to the CLI's one list envelope (issue #2440).
|
|
2158
|
-
*
|
|
2159
|
-
* The registered operation decides the response shape, so the normalization
|
|
2160
|
-
* is conditional — see {@link normalizeDatabaseOperationResult}. Everything
|
|
2161
|
-
* else (a `count`, an `aggregate`, a mutation, a `returnField: "all"`
|
|
2162
|
-
* pipeline) is returned exactly as the server sent it.
|
|
2163
|
-
*/
|
|
2164
|
-
async executeDatabaseOperation(appId, databaseId, operationName, data, options) {
|
|
2165
|
-
const path = `/app/${appId}/api/databases/${databaseId}/operations/${encodeURIComponent(operationName)}/execute`;
|
|
2166
|
-
const extraHeaders = {};
|
|
2167
|
-
if (options?.timing) {
|
|
2168
|
-
extraHeaders["X-Timing"] = "true";
|
|
2169
|
-
}
|
|
2170
|
-
return normalizeDatabaseOperationResult(await this.request(path, {
|
|
2171
|
-
method: "POST",
|
|
2172
|
-
body: JSON.stringify(data || {}),
|
|
2173
|
-
headers: extraHeaders,
|
|
2174
|
-
}));
|
|
2175
|
-
}
|
|
2176
|
-
/**
|
|
2177
|
-
* Execute a registered batch (bulk) database operation. Posts a chunk of
|
|
2178
|
-
* items to the canonical `operations/:name/batch` endpoint (the same one the
|
|
2179
|
-
* client library's `executeBatch` uses — NOT the deprecated `import-bulk`
|
|
2180
|
-
* alias). Used by `databases import-csv`.
|
|
2181
|
-
*
|
|
2182
|
-
* @returns `{ imported, failed }` — DO-level write outcome counts. Per-item
|
|
2183
|
-
* validation/access failures abort the whole chunk with a 4xx (thrown).
|
|
2184
|
-
*/
|
|
2185
|
-
async executeBatch(appId, databaseId, operationName, batch) {
|
|
2186
|
-
return this.post(`/app/${appId}/api/databases/${databaseId}/operations/${encodeURIComponent(operationName)}/batch`, { batch });
|
|
2187
|
-
}
|
|
2188
|
-
// ============================================
|
|
2189
2046
|
// DATABASE INDEXES
|
|
2190
2047
|
// ============================================
|
|
2191
2048
|
async listDatabaseIndexes(appId, databaseId, modelName) {
|
|
@@ -2218,7 +2075,7 @@ export class ApiClient {
|
|
|
2218
2075
|
// Issue #1336 (codex round-1 P2): `dryRun` runs every create-time
|
|
2219
2076
|
// validation (inline CEL rule lint, manifest shape, schema TOML parse)
|
|
2220
2077
|
// WITHOUT persisting, so a fresh-type `config push --dry-run` surfaces a
|
|
2221
|
-
// malformed
|
|
2078
|
+
// malformed rule or manifest the same way the real POST would.
|
|
2222
2079
|
options) {
|
|
2223
2080
|
const query = options?.dryRun ? "?dryRun=true" : "";
|
|
2224
2081
|
return this.post(`/app/${appId}/api/databases/types${query}`, data);
|
|
@@ -2239,105 +2096,14 @@ export class ApiClient {
|
|
|
2239
2096
|
return this.delete(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}${query}`);
|
|
2240
2097
|
}
|
|
2241
2098
|
/**
|
|
2242
|
-
* Issue #666 Phase 3: ask the server to scaffold a TOML schema from
|
|
2243
|
-
*
|
|
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.
|
|
2244
2102
|
*/
|
|
2245
2103
|
async scaffoldDatabaseTypeSchema(appId, databaseType) {
|
|
2246
2104
|
return this.post(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/schema:scaffold`, {});
|
|
2247
2105
|
}
|
|
2248
2106
|
// ============================================
|
|
2249
|
-
// DATABASE TYPE OPERATIONS
|
|
2250
|
-
// ============================================
|
|
2251
|
-
async listDatabaseTypeOperations(appId, databaseType) {
|
|
2252
|
-
return this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations`);
|
|
2253
|
-
}
|
|
2254
|
-
async getDatabaseTypeOperation(appId, databaseType, name) {
|
|
2255
|
-
return this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations/${encodeURIComponent(name)}`);
|
|
2256
|
-
}
|
|
2257
|
-
async createDatabaseTypeOperation(appId, databaseType, data,
|
|
2258
|
-
// Issue #813 (1A): when `dryRun` is set the server runs the op-edit gate
|
|
2259
|
-
// without persisting — used by `config push --dry-run` to surface gate
|
|
2260
|
-
// failures the real push would hit. `schemaOverride` lets the gate run
|
|
2261
|
-
// against the schema the SAME push is about to land (so an op that depends
|
|
2262
|
-
// on a new field isn't falsely rejected against the stale stored schema).
|
|
2263
|
-
//
|
|
2264
|
-
// Issue #915 (defect a, follow-up): for a FRESH db-type the parent config
|
|
2265
|
-
// does not exist on the server yet, so the server's "access required"
|
|
2266
|
-
// check has no `defaultAccess` to fall back on. Thread the TOML-declared
|
|
2267
|
-
// type-level `defaultAccess` so an op that omits `access` (intending to
|
|
2268
|
-
// inherit it after the type is created) isn't falsely rejected during the
|
|
2269
|
-
// dry-run. Server only trusts this on the fresh-type dry-run path.
|
|
2270
|
-
options) {
|
|
2271
|
-
const query = options?.dryRun ? "?dryRun=true" : "";
|
|
2272
|
-
let body = data;
|
|
2273
|
-
if (options?.dryRun && options.schemaOverride !== undefined) {
|
|
2274
|
-
body = { ...body, schemaOverride: options.schemaOverride };
|
|
2275
|
-
}
|
|
2276
|
-
if (options?.dryRun && options.defaultAccess !== undefined) {
|
|
2277
|
-
body = { ...body, defaultAccess: options.defaultAccess };
|
|
2278
|
-
}
|
|
2279
|
-
if (options?.dryRun && options.metadataManifestOverride !== undefined) {
|
|
2280
|
-
body = { ...body, metadataManifestOverride: options.metadataManifestOverride };
|
|
2281
|
-
}
|
|
2282
|
-
return this.post(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations${query}`, body);
|
|
2283
|
-
}
|
|
2284
|
-
async updateDatabaseTypeOperation(appId, databaseType, name, data, expectedModifiedAt,
|
|
2285
|
-
// Issue #813 (1A): dry-run runs the op-edit gate without persisting.
|
|
2286
|
-
// `schemaOverride` gates against the schema the same push is landing.
|
|
2287
|
-
// Issue #1336: `metadataManifestOverride` gates the op-access lint against
|
|
2288
|
-
// the manifest the same push is landing (see `createDatabaseTypeOperation`).
|
|
2289
|
-
options) {
|
|
2290
|
-
let body = expectedModifiedAt ? { ...data, expectedModifiedAt } : { ...data };
|
|
2291
|
-
if (options?.dryRun && options.schemaOverride !== undefined) {
|
|
2292
|
-
body = { ...body, schemaOverride: options.schemaOverride };
|
|
2293
|
-
}
|
|
2294
|
-
if (options?.dryRun && options.metadataManifestOverride !== undefined) {
|
|
2295
|
-
body = { ...body, metadataManifestOverride: options.metadataManifestOverride };
|
|
2296
|
-
}
|
|
2297
|
-
const query = options?.dryRun ? "?dryRun=true" : "";
|
|
2298
|
-
return this.patch(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations/${encodeURIComponent(name)}${query}`, body);
|
|
2299
|
-
}
|
|
2300
|
-
async deleteDatabaseTypeOperation(appId, databaseType, name) {
|
|
2301
|
-
return this.delete(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/operations/${encodeURIComponent(name)}`);
|
|
2302
|
-
}
|
|
2303
|
-
// ============================================
|
|
2304
|
-
// DATABASE TYPE SUBSCRIPTIONS (#740 / #803)
|
|
2305
|
-
// ============================================
|
|
2306
|
-
//
|
|
2307
|
-
// Transparent passthroughs against the server's type-scoped subscription
|
|
2308
|
-
// routes (GET/POST/PUT/DELETE `/databases/types/:type/subscriptions[/:key]`).
|
|
2309
|
-
// The wire format is authoritative in the controller
|
|
2310
|
-
// (`database-type-subscriptions-controller.ts`): create requires
|
|
2311
|
-
// `subscriptionKey`, `displayName`, `modelName`, `filter` (CEL), `access`
|
|
2312
|
-
// (CEL); optional `description`, `select` (string[]), `emit`
|
|
2313
|
-
// (enter/update/leave subset), `params` (object, ≤5 entries), `status`.
|
|
2314
|
-
//
|
|
2315
|
-
// The list endpoint wraps results in `{ items: [...] }` (unlike operations,
|
|
2316
|
-
// which returns a bare array). We unwrap here so callers get an array,
|
|
2317
|
-
// matching `listDatabaseTypeOperations`.
|
|
2318
|
-
async listDatabaseTypeSubscriptions(appId, databaseType) {
|
|
2319
|
-
const result = await this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions`);
|
|
2320
|
-
if (Array.isArray(result))
|
|
2321
|
-
return result;
|
|
2322
|
-
return Array.isArray(result?.items) ? result.items : [];
|
|
2323
|
-
}
|
|
2324
|
-
async getDatabaseTypeSubscription(appId, databaseType, subscriptionKey) {
|
|
2325
|
-
return this.get(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions/${encodeURIComponent(subscriptionKey)}`);
|
|
2326
|
-
}
|
|
2327
|
-
async createDatabaseTypeSubscription(appId, databaseType, data) {
|
|
2328
|
-
return this.post(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions`, data);
|
|
2329
|
-
}
|
|
2330
|
-
async updateDatabaseTypeSubscription(appId, databaseType, subscriptionKey, data,
|
|
2331
|
-
// #2731 B10 — optimistic concurrency, as the sibling operation update has
|
|
2332
|
-
// had. Omitted (by `--force`, and by every caller predating it) means the
|
|
2333
|
-
// write stays unconditional.
|
|
2334
|
-
expectedModifiedAt) {
|
|
2335
|
-
return this.put(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions/${encodeURIComponent(subscriptionKey)}`, expectedModifiedAt ? { ...data, expectedModifiedAt } : data);
|
|
2336
|
-
}
|
|
2337
|
-
async deleteDatabaseTypeSubscription(appId, databaseType, subscriptionKey) {
|
|
2338
|
-
return this.delete(`/app/${appId}/api/databases/types/${encodeURIComponent(databaseType)}/subscriptions/${encodeURIComponent(subscriptionKey)}`);
|
|
2339
|
-
}
|
|
2340
|
-
// ============================================
|
|
2341
2107
|
// GROUPS
|
|
2342
2108
|
// ============================================
|
|
2343
2109
|
async listGroups(appId, params) {
|
|
@@ -2655,51 +2421,6 @@ export class ApiClient {
|
|
|
2655
2421
|
async importDocumentState(appId, documentId, stateBase64) {
|
|
2656
2422
|
return this.post(`/app/${appId}/api/documents/${documentId}/import/state`, { state: stateBase64 });
|
|
2657
2423
|
}
|
|
2658
|
-
/**
|
|
2659
|
-
* Upload one artifact of a large document's import chain (#2816,
|
|
2660
|
-
* behavior 20).
|
|
2661
|
-
*
|
|
2662
|
-
* The bytes travel raw and unmodified: the manifest's digest is over the
|
|
2663
|
-
* STORED bytes, so re-encoding a chunk here would fail its own verification
|
|
2664
|
-
* on install. The query says which artifact it is — the server derives the
|
|
2665
|
-
* key from the document it belongs to, so nothing here composes one.
|
|
2666
|
-
*/
|
|
2667
|
-
async uploadDocumentChainArtifact(appId, documentId, query, body) {
|
|
2668
|
-
const credentials = await this.ensureAuthenticated();
|
|
2669
|
-
const search = new URLSearchParams();
|
|
2670
|
-
for (const [key, value] of Object.entries(query)) {
|
|
2671
|
-
search.set(key, String(value));
|
|
2672
|
-
}
|
|
2673
|
-
const url = `${credentials.serverUrl}/app/${appId}/api/documents/${documentId}` +
|
|
2674
|
-
`/import/chain/artifact?${search.toString()}`;
|
|
2675
|
-
const headers = {
|
|
2676
|
-
Authorization: `Bearer ${credentials.accessToken}`,
|
|
2677
|
-
"Content-Type": "application/octet-stream",
|
|
2678
|
-
};
|
|
2679
|
-
if (credentials.globalAdminAppId) {
|
|
2680
|
-
headers["X-Global-Admin-App-Id"] = credentials.globalAdminAppId;
|
|
2681
|
-
}
|
|
2682
|
-
const response = await fetchWithTLS(url, {
|
|
2683
|
-
method: "POST",
|
|
2684
|
-
headers,
|
|
2685
|
-
body: body,
|
|
2686
|
-
});
|
|
2687
|
-
if (!response.ok) {
|
|
2688
|
-
// #3403 — through the shared parser: reading `error` alone dropped the
|
|
2689
|
-
// envelope's `code` and `details`, so the refusal reached the operator
|
|
2690
|
-
// (and `primitive documents import`) with nothing to branch on.
|
|
2691
|
-
throw await blobFailure(response, "Failed to upload import artifact: ");
|
|
2692
|
-
}
|
|
2693
|
-
return await response.json().catch(() => ({}));
|
|
2694
|
-
}
|
|
2695
|
-
/** Start installing an uploaded chain (#2816, behavior 20). */
|
|
2696
|
-
async installDocumentChain(appId, documentId, plan) {
|
|
2697
|
-
return this.post(`/app/${appId}/api/documents/${documentId}/import/chain`, plan);
|
|
2698
|
-
}
|
|
2699
|
-
/** How far a document's chain install has got (#2816, behavior 20). */
|
|
2700
|
-
async getDocumentChainInstall(appId, documentId) {
|
|
2701
|
-
return this.get(`/app/${appId}/api/documents/${documentId}/import/chain`);
|
|
2702
|
-
}
|
|
2703
2424
|
async getDocument(appId, documentId) {
|
|
2704
2425
|
return this.get(`/app/${appId}/api/documents/${documentId}`);
|
|
2705
2426
|
}
|
|
@@ -2793,10 +2514,19 @@ export class ApiClient {
|
|
|
2793
2514
|
/**
|
|
2794
2515
|
* A record-log document's room (#4306): `GET documents/:id/room` →
|
|
2795
2516
|
* `{ ok, appId, documentId, documentFormat, room }`, `room` null for a
|
|
2796
|
-
* format that has no record room.
|
|
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.
|
|
2797
2519
|
*/
|
|
2798
|
-
async getDocumentRoom(appId, documentId) {
|
|
2799
|
-
|
|
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}` : ""}`);
|
|
2800
2530
|
}
|
|
2801
2531
|
/**
|
|
2802
2532
|
* A large document's snapshot builds, newest first, one page (#3432).
|
|
@@ -2831,9 +2561,13 @@ export class ApiClient {
|
|
|
2831
2561
|
async getDocumentIngest(appId, documentId, sessionId) {
|
|
2832
2562
|
return this.get(`/app/${appId}/api/documents/${documentId}/ingest/${encodeURIComponent(sessionId)}`);
|
|
2833
2563
|
}
|
|
2834
|
-
/**
|
|
2835
|
-
|
|
2836
|
-
|
|
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);
|
|
2837
2571
|
}
|
|
2838
2572
|
/**
|
|
2839
2573
|
* Upload one chunk of a bulk-load session's artifact (#3435).
|