@tinycloud/sdk-services 3.2.0-beta.2 → 3.2.0-beta.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/dist/{BaseService-DWbPbov7.d.cts → BaseService-BDQXjWMx.d.cts} +1 -1
- package/dist/{BaseService-B_UKhVht.d.ts → BaseService-Di_hVfUV.d.ts} +1 -1
- package/dist/encryption/index.cjs +7 -1
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js +7 -1
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +605 -357
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -26
- package/dist/index.d.ts +37 -26
- package/dist/index.js +600 -357
- package/dist/index.js.map +1 -1
- package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
- package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
- package/dist/kv/index.cjs +540 -338
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +18 -468
- package/dist/kv/index.d.ts +18 -468
- package/dist/kv/index.js +534 -337
- package/dist/kv/index.js.map +1 -1
- package/dist/kv/replication/index.cjs +1398 -0
- package/dist/kv/replication/index.cjs.map +1 -0
- package/dist/kv/replication/index.d.cts +10 -0
- package/dist/kv/replication/index.d.ts +10 -0
- package/dist/kv/replication/index.js +1365 -0
- package/dist/kv/replication/index.js.map +1 -0
- package/dist/kv/replication/prefix.cjs +43 -0
- package/dist/kv/replication/prefix.cjs.map +1 -0
- package/dist/kv/replication/prefix.d.cts +6 -0
- package/dist/kv/replication/prefix.d.ts +6 -0
- package/dist/kv/replication/prefix.js +17 -0
- package/dist/kv/replication/prefix.js.map +1 -0
- package/dist/scope-BKge7zDT.d.ts +957 -0
- package/dist/scope-C05VVAXH.d.cts +957 -0
- package/dist/sql/index.cjs +12 -6
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +2 -2
- package/dist/sql/index.d.ts +2 -2
- package/dist/sql/index.js +12 -6
- package/dist/sql/index.js.map +1 -1
- package/dist/{types-CVwwxqXF.d.cts → types-7A5rHWRY.d.cts} +10 -1
- package/dist/{types-CVwwxqXF.d.ts → types-7A5rHWRY.d.ts} +10 -1
- package/package.json +31 -1
package/dist/index.js
CHANGED
|
@@ -60,7 +60,12 @@ var TelemetryEvents = {
|
|
|
60
60
|
SERVICE_ERROR: "service.error",
|
|
61
61
|
SERVICE_RETRY: "service.retry",
|
|
62
62
|
SESSION_CHANGED: "session.changed",
|
|
63
|
-
SESSION_EXPIRED: "session.expired"
|
|
63
|
+
SESSION_EXPIRED: "session.expired",
|
|
64
|
+
REPLICATION_READ: "replication.read",
|
|
65
|
+
REPLICATION_WRITE: "replication.write",
|
|
66
|
+
REPLICATION_SYNC: "replication.sync",
|
|
67
|
+
REPLICATION_STATE: "replication.state",
|
|
68
|
+
REPLICATION_DIVERGENCE: "replication.divergence"
|
|
64
69
|
};
|
|
65
70
|
function ok(data) {
|
|
66
71
|
return { ok: true, data };
|
|
@@ -86,9 +91,34 @@ var SAFE_NUMBER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
86
91
|
"endedAt",
|
|
87
92
|
"startedAt",
|
|
88
93
|
"status",
|
|
89
|
-
"timestamp"
|
|
94
|
+
"timestamp",
|
|
95
|
+
"latencyMs",
|
|
96
|
+
"stalenessMs",
|
|
97
|
+
"count",
|
|
98
|
+
"changes",
|
|
99
|
+
"deleted",
|
|
100
|
+
"fetched",
|
|
101
|
+
"pages",
|
|
102
|
+
"lagMs",
|
|
103
|
+
"pendingCleared"
|
|
90
104
|
]);
|
|
91
105
|
var SAFE_BOOLEAN_FIELDS = /* @__PURE__ */ new Set(["authenticated", "ok", "persisted"]);
|
|
106
|
+
var SAFE_REPLICATION_FIELDS = {
|
|
107
|
+
source: ["replica", "network", "none"],
|
|
108
|
+
reason: ["hit", "absent", "deleted", "content_missing", "coverage_incomplete", "not_covered", "pending_write", "grant_missing", "grant_expired", "grant_revoked", "grant_not_yet_valid", "stale", "replica_error", "runtime_unsupported", "replica_unavailable", "unsupported_option", "network_cursor", "cursor_restart", "aborted", "REPLICA_BEHIND_OWN_WRITES", "REPLICA_UNPROVEN_SINCE_START", "NETWORK_REQUESTED"],
|
|
109
|
+
op: ["get", "list", "put", "delete", "batchPut"],
|
|
110
|
+
trigger: ["start", "interval", "stale_read", "manual"],
|
|
111
|
+
outcome: ["found", "not_found", "error", "committed", "failed", "ambiguous", "ok", "busy", "aborted"],
|
|
112
|
+
class: ["offline", "authority", "storage", "node"],
|
|
113
|
+
state: ["opened", "grant_installed", "grant_missing", "runtime_unsupported", "unavailable", "revoked", "recreated", "purged", "purge_failed", "pending_store_error", "pinned", "pending_cleared", "closed", "idle", "ready"],
|
|
114
|
+
kind: ["value", "missing_local", "extra_local", "keys", "order"],
|
|
115
|
+
coverage: ["empty", "bootstrapping", "complete"],
|
|
116
|
+
authority: ["valid", "expired", "revoked", "not-yet-valid"],
|
|
117
|
+
code: ["NETWORK_ERROR", "TIMEOUT", "ABORTED", "REPLICA_BUSY", "REPLICA_BEHIND_OWN_WRITES", "REPLICA_UNPROVEN_SINCE_START", "NETWORK_REQUESTED", "INTEGRITY_ERROR", "STORAGE_ERROR", "REPLICA_CLOSED", "RUNTIME_UNSUPPORTED", "GRANT_EXPIRED", "GRANT_REVOKED", "GRANT_NOT_YET_VALID", "GRANT_MISSING", "GRANT_INVALID", "SOURCE_CHANGED", "PROTOCOL_ERROR", "SCOPE_VIOLATION", "NODE_ERROR", "CONTENT_MISMATCH", "STORAGE_FULL"],
|
|
118
|
+
pendingState: ["in_flight", "committed", "ambiguous"],
|
|
119
|
+
strategy: ["session", "minted", "installed"],
|
|
120
|
+
verify: ["match", "diverged", "error", "aborted"]
|
|
121
|
+
};
|
|
92
122
|
function finiteNumber(value) {
|
|
93
123
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
94
124
|
}
|
|
@@ -125,6 +155,12 @@ function projectDiagnosticData(value) {
|
|
|
125
155
|
const boolean = read(value, key);
|
|
126
156
|
if (typeof boolean === "boolean") projected[key] = boolean;
|
|
127
157
|
}
|
|
158
|
+
for (const [key, allowed] of Object.entries(SAFE_REPLICATION_FIELDS)) {
|
|
159
|
+
const candidate = read(value, key);
|
|
160
|
+
if (typeof candidate === "string" && allowed.includes(candidate)) {
|
|
161
|
+
projected[key] = candidate;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
128
164
|
const url = read(value, "url");
|
|
129
165
|
if (url !== void 0) projected.url = REDACTED;
|
|
130
166
|
const error = read(value, "error");
|
|
@@ -749,6 +785,12 @@ var ServiceContext = class {
|
|
|
749
785
|
get abortSignal() {
|
|
750
786
|
return this._abortController.signal;
|
|
751
787
|
}
|
|
788
|
+
get operationAbortSignal() {
|
|
789
|
+
return this._operationAbortSignal;
|
|
790
|
+
}
|
|
791
|
+
setOperationAbortSignal(signal) {
|
|
792
|
+
this._operationAbortSignal = signal;
|
|
793
|
+
}
|
|
752
794
|
/**
|
|
753
795
|
* Permanently retire this graph after its owner installs a replacement.
|
|
754
796
|
* Unlike `abort()`, retirement never creates a fresh controller, so captured
|
|
@@ -1500,6 +1542,7 @@ var BaseService = class {
|
|
|
1500
1542
|
const parents = [
|
|
1501
1543
|
this.abortController.signal,
|
|
1502
1544
|
this.context?.abortSignal,
|
|
1545
|
+
this.context?.operationAbortSignal,
|
|
1503
1546
|
signal
|
|
1504
1547
|
].filter((parent) => parent !== void 0);
|
|
1505
1548
|
for (const parent of parents) {
|
|
@@ -1745,14 +1788,28 @@ var KVService = class extends BaseService {
|
|
|
1745
1788
|
*/
|
|
1746
1789
|
constructor(config = {}) {
|
|
1747
1790
|
super();
|
|
1791
|
+
this.readThrough = null;
|
|
1792
|
+
this.readThroughReady = null;
|
|
1748
1793
|
this._config = config;
|
|
1749
1794
|
}
|
|
1795
|
+
/** Delay KV routing until an asynchronously loaded read-through is attached. */
|
|
1796
|
+
setReadThroughReady(ready) {
|
|
1797
|
+
const settled = ready.then(() => void 0, () => void 0);
|
|
1798
|
+
this.readThroughReady = settled;
|
|
1799
|
+
void settled.then(() => {
|
|
1800
|
+
if (this.readThroughReady === settled) this.readThroughReady = null;
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1750
1803
|
/**
|
|
1751
1804
|
* Get the service configuration.
|
|
1752
1805
|
*/
|
|
1753
1806
|
get config() {
|
|
1754
1807
|
return this._config;
|
|
1755
1808
|
}
|
|
1809
|
+
/** Install or remove the optional replication read-through policy. */
|
|
1810
|
+
setReadThrough(readThrough) {
|
|
1811
|
+
this.readThrough = readThrough;
|
|
1812
|
+
}
|
|
1756
1813
|
handleQuotaErrorResponse(response, errorText, key) {
|
|
1757
1814
|
if (response.status !== 402 && response.status !== 413) {
|
|
1758
1815
|
return void 0;
|
|
@@ -2006,6 +2063,7 @@ var KVService = class extends BaseService {
|
|
|
2006
2063
|
return aligned;
|
|
2007
2064
|
}
|
|
2008
2065
|
async batchRead(keys, action, options) {
|
|
2066
|
+
if (this.readThroughReady !== null) await this.readThroughReady;
|
|
2009
2067
|
if (!this.requireAuth()) return err(authRequiredError("kv"));
|
|
2010
2068
|
if (keys.length === 0) return ok({ results: [], count: 0 });
|
|
2011
2069
|
if (keys.length > MAX_KV_BATCH_READ_ITEMS) {
|
|
@@ -2256,6 +2314,7 @@ var KVService = class extends BaseService {
|
|
|
2256
2314
|
*/
|
|
2257
2315
|
async get(key, options) {
|
|
2258
2316
|
return this.withTelemetry("get", key, async () => {
|
|
2317
|
+
if (this.readThroughReady !== null) await this.readThroughReady;
|
|
2259
2318
|
if (!this.requireAuth()) {
|
|
2260
2319
|
return err(authRequiredError("kv"));
|
|
2261
2320
|
}
|
|
@@ -2269,64 +2328,38 @@ var KVService = class extends BaseService {
|
|
|
2269
2328
|
const path = this.getFullPath(key, options?.prefix);
|
|
2270
2329
|
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2271
2330
|
try {
|
|
2272
|
-
const
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
response,
|
|
2295
|
-
errorText2,
|
|
2296
|
-
[path],
|
|
2297
|
-
KVAction.GET,
|
|
2298
|
-
structuredCapability ? { permissionHint, ...structuredCapability } : {}
|
|
2299
|
-
);
|
|
2300
|
-
}
|
|
2301
|
-
if (response.status === 404) {
|
|
2302
|
-
return await this.classifyNotFound(response, key);
|
|
2303
|
-
}
|
|
2304
|
-
const errorText = await response.text();
|
|
2305
|
-
if (response.status === 413) {
|
|
2306
|
-
return err(serviceError(
|
|
2307
|
-
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
2308
|
-
`KV value at key ${JSON.stringify(key)} exceeds the requested response limit`,
|
|
2309
|
-
"kv",
|
|
2310
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2311
|
-
));
|
|
2331
|
+
const network = () => this.getFromNetwork(key, path, options, request.signal);
|
|
2332
|
+
if (options?.source === "network") {
|
|
2333
|
+
const observer = this.readThrough;
|
|
2334
|
+
if (observer === null) return await network();
|
|
2335
|
+
let outcome = "error";
|
|
2336
|
+
const startedAt = Date.now();
|
|
2337
|
+
try {
|
|
2338
|
+
const result = await network();
|
|
2339
|
+
outcome = result.ok ? "found" : result.error.code === ErrorCodes.KV_NOT_FOUND ? "not_found" : "error";
|
|
2340
|
+
return result;
|
|
2341
|
+
} finally {
|
|
2342
|
+
try {
|
|
2343
|
+
observer.observeNetworkRequested({
|
|
2344
|
+
op: "get",
|
|
2345
|
+
space: this.context.session.spaceId,
|
|
2346
|
+
path,
|
|
2347
|
+
reason: "NETWORK_REQUESTED",
|
|
2348
|
+
outcome,
|
|
2349
|
+
latencyMs: Date.now() - startedAt
|
|
2350
|
+
});
|
|
2351
|
+
} catch {
|
|
2352
|
+
}
|
|
2312
2353
|
}
|
|
2313
|
-
return err(
|
|
2314
|
-
serviceError(
|
|
2315
|
-
ErrorCodes.NETWORK_ERROR,
|
|
2316
|
-
`Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2317
|
-
"kv",
|
|
2318
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2319
|
-
)
|
|
2320
|
-
);
|
|
2321
2354
|
}
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2355
|
+
if (this.readThrough === null) return await network();
|
|
2356
|
+
return await this.readThrough.get({
|
|
2357
|
+
space: this.context.session.spaceId,
|
|
2358
|
+
key,
|
|
2359
|
+
path,
|
|
2360
|
+
options,
|
|
2361
|
+
signal: request.signal,
|
|
2362
|
+
network
|
|
2330
2363
|
});
|
|
2331
2364
|
} catch (error) {
|
|
2332
2365
|
return err(wrapError("kv", error));
|
|
@@ -2335,6 +2368,56 @@ var KVService = class extends BaseService {
|
|
|
2335
2368
|
}
|
|
2336
2369
|
});
|
|
2337
2370
|
}
|
|
2371
|
+
async getFromNetwork(key, path, options, signal) {
|
|
2372
|
+
const response = await this.invokeOperation(
|
|
2373
|
+
path,
|
|
2374
|
+
KVAction.GET,
|
|
2375
|
+
void 0,
|
|
2376
|
+
signal,
|
|
2377
|
+
options?.maxResponseBytes === void 0 ? void 0 : { "x-tinycloud-max-response-bytes": String(options.maxResponseBytes) }
|
|
2378
|
+
);
|
|
2379
|
+
if (!response.ok) {
|
|
2380
|
+
if (response.status === 401 || response.status === 403) {
|
|
2381
|
+
const errorText2 = await this.readAuthorizationText(response);
|
|
2382
|
+
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
2383
|
+
const structuredCapability = permissionHint?.service === "tinycloud.kv" && permissionHint.space === this.context.session.spaceId && permissionHint.path === path ? validatedCapabilityOf({
|
|
2384
|
+
service: "kv",
|
|
2385
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
2386
|
+
meta: {
|
|
2387
|
+
status: response.status,
|
|
2388
|
+
resource: `${this.context.session.spaceId}/kv/${path}`,
|
|
2389
|
+
requiredAction: KVAction.GET
|
|
2390
|
+
}
|
|
2391
|
+
}) : void 0;
|
|
2392
|
+
return this.authorizationFailure(
|
|
2393
|
+
`Failed to get key ${JSON.stringify(key)}`,
|
|
2394
|
+
response,
|
|
2395
|
+
errorText2,
|
|
2396
|
+
[path],
|
|
2397
|
+
KVAction.GET,
|
|
2398
|
+
structuredCapability ? { permissionHint, ...structuredCapability } : {}
|
|
2399
|
+
);
|
|
2400
|
+
}
|
|
2401
|
+
if (response.status === 404) return this.classifyNotFound(response, key);
|
|
2402
|
+
const errorText = await response.text();
|
|
2403
|
+
if (response.status === 413) {
|
|
2404
|
+
return err(serviceError(
|
|
2405
|
+
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
2406
|
+
`KV value at key ${JSON.stringify(key)} exceeds the requested response limit`,
|
|
2407
|
+
"kv",
|
|
2408
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2409
|
+
));
|
|
2410
|
+
}
|
|
2411
|
+
return err(serviceError(
|
|
2412
|
+
ErrorCodes.NETWORK_ERROR,
|
|
2413
|
+
`Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2414
|
+
"kv",
|
|
2415
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2416
|
+
));
|
|
2417
|
+
}
|
|
2418
|
+
const data = await this.parseResponse(response, options?.raw, options?.binary);
|
|
2419
|
+
return ok({ data, headers: this.createResponseHeaders(response.headers) });
|
|
2420
|
+
}
|
|
2338
2421
|
async batchGet(keys, options) {
|
|
2339
2422
|
return this.withTelemetry(
|
|
2340
2423
|
"batchGet",
|
|
@@ -2347,6 +2430,7 @@ var KVService = class extends BaseService {
|
|
|
2347
2430
|
*/
|
|
2348
2431
|
async put(key, value, options) {
|
|
2349
2432
|
return this.withTelemetry("put", key, async () => {
|
|
2433
|
+
if (this.readThroughReady !== null) await this.readThroughReady;
|
|
2350
2434
|
if (!this.requireAuth()) {
|
|
2351
2435
|
return err(authRequiredError("kv"));
|
|
2352
2436
|
}
|
|
@@ -2361,63 +2445,15 @@ var KVService = class extends BaseService {
|
|
|
2361
2445
|
const body = this.serializePutValue(value, options?.contentType);
|
|
2362
2446
|
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2363
2447
|
try {
|
|
2364
|
-
const
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
{
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
);
|
|
2374
|
-
if (response.status === 401 || response.status === 403) {
|
|
2375
|
-
return this.authorizationFailure(
|
|
2376
|
-
`Failed to put key ${JSON.stringify(key)}`,
|
|
2377
|
-
response,
|
|
2378
|
-
await this.readAuthorizationText(response),
|
|
2379
|
-
[path],
|
|
2380
|
-
KVAction.PUT
|
|
2381
|
-
);
|
|
2382
|
-
}
|
|
2383
|
-
if (!response.ok) {
|
|
2384
|
-
const errorText = await response.text();
|
|
2385
|
-
if (response.status === 412) {
|
|
2386
|
-
return err(serviceError(
|
|
2387
|
-
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
2388
|
-
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
2389
|
-
"kv",
|
|
2390
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2391
|
-
));
|
|
2392
|
-
}
|
|
2393
|
-
if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
|
|
2394
|
-
return err(serviceError(
|
|
2395
|
-
ErrorCodes.KV_CONFLICT,
|
|
2396
|
-
`Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
|
|
2397
|
-
"kv",
|
|
2398
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2399
|
-
));
|
|
2400
|
-
}
|
|
2401
|
-
const quotaError = this.handleQuotaErrorResponse(
|
|
2402
|
-
response,
|
|
2403
|
-
errorText,
|
|
2404
|
-
key
|
|
2405
|
-
);
|
|
2406
|
-
if (quotaError) {
|
|
2407
|
-
return quotaError;
|
|
2408
|
-
}
|
|
2409
|
-
return err(
|
|
2410
|
-
serviceError(
|
|
2411
|
-
ErrorCodes.KV_WRITE_FAILED,
|
|
2412
|
-
`Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2413
|
-
"kv",
|
|
2414
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2415
|
-
)
|
|
2416
|
-
);
|
|
2417
|
-
}
|
|
2418
|
-
return ok({
|
|
2419
|
-
data: void 0,
|
|
2420
|
-
headers: this.createResponseHeaders(response.headers)
|
|
2448
|
+
const network = () => this.putToNetwork(key, path, body, options, request.signal);
|
|
2449
|
+
if (this.readThrough === null) return await network();
|
|
2450
|
+
return await this.readThrough.write({
|
|
2451
|
+
op: "put",
|
|
2452
|
+
space: this.context.session.spaceId,
|
|
2453
|
+
entries: [{ path, body }],
|
|
2454
|
+
signal: request.signal,
|
|
2455
|
+
conditional: options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0,
|
|
2456
|
+
network
|
|
2421
2457
|
});
|
|
2422
2458
|
} catch (error) {
|
|
2423
2459
|
return err(wrapError("kv", error));
|
|
@@ -2426,11 +2462,64 @@ var KVService = class extends BaseService {
|
|
|
2426
2462
|
}
|
|
2427
2463
|
});
|
|
2428
2464
|
}
|
|
2465
|
+
async putToNetwork(key, path, body, options, signal) {
|
|
2466
|
+
const response = await this.invokeOperation(
|
|
2467
|
+
path,
|
|
2468
|
+
KVAction.PUT,
|
|
2469
|
+
body,
|
|
2470
|
+
signal,
|
|
2471
|
+
{
|
|
2472
|
+
...options?.ifMatch === void 0 ? {} : { "if-match": options.ifMatch },
|
|
2473
|
+
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
2474
|
+
}
|
|
2475
|
+
);
|
|
2476
|
+
if (response.status === 401 || response.status === 403) {
|
|
2477
|
+
return this.authorizationFailure(
|
|
2478
|
+
`Failed to put key ${JSON.stringify(key)}`,
|
|
2479
|
+
response,
|
|
2480
|
+
await this.readAuthorizationText(response),
|
|
2481
|
+
[path],
|
|
2482
|
+
KVAction.PUT
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
if (!response.ok) {
|
|
2486
|
+
const errorText = await response.text();
|
|
2487
|
+
if (response.status === 412) {
|
|
2488
|
+
return err(serviceError(
|
|
2489
|
+
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
2490
|
+
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
2491
|
+
"kv",
|
|
2492
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2493
|
+
));
|
|
2494
|
+
}
|
|
2495
|
+
if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
|
|
2496
|
+
return err(serviceError(
|
|
2497
|
+
ErrorCodes.KV_CONFLICT,
|
|
2498
|
+
`Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
|
|
2499
|
+
"kv",
|
|
2500
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2501
|
+
));
|
|
2502
|
+
}
|
|
2503
|
+
const quotaError = this.handleQuotaErrorResponse(response, errorText, key);
|
|
2504
|
+
if (quotaError) return quotaError;
|
|
2505
|
+
return err(serviceError(
|
|
2506
|
+
ErrorCodes.KV_WRITE_FAILED,
|
|
2507
|
+
`Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2508
|
+
"kv",
|
|
2509
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2510
|
+
));
|
|
2511
|
+
}
|
|
2512
|
+
return ok({
|
|
2513
|
+
data: void 0,
|
|
2514
|
+
headers: this.createResponseHeaders(response.headers)
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2429
2517
|
/**
|
|
2430
2518
|
* Store multiple values in one TinyCloud KV invocation.
|
|
2431
2519
|
*/
|
|
2432
2520
|
async batchPut(items, options) {
|
|
2433
2521
|
return this.withTelemetry("batchPut", String(items.length), async () => {
|
|
2522
|
+
if (this.readThroughReady !== null) await this.readThroughReady;
|
|
2434
2523
|
if (!this.requireAuth()) {
|
|
2435
2524
|
return err(authRequiredError("kv"));
|
|
2436
2525
|
}
|
|
@@ -2461,155 +2550,177 @@ var KVService = class extends BaseService {
|
|
|
2461
2550
|
}
|
|
2462
2551
|
seen.add(path);
|
|
2463
2552
|
}
|
|
2464
|
-
let requestMayHaveDispatched = false;
|
|
2465
2553
|
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2466
2554
|
try {
|
|
2467
|
-
const
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
session,
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2555
|
+
const network = () => this.batchPutToNetwork(items, paths, request.signal);
|
|
2556
|
+
if (this.readThrough === null) return await network();
|
|
2557
|
+
const entries = items.map((item, index) => ({
|
|
2558
|
+
path: paths[index],
|
|
2559
|
+
body: this.serializeBatchPutValue(item)
|
|
2560
|
+
}));
|
|
2561
|
+
return await this.readThrough.write({
|
|
2562
|
+
op: "batchPut",
|
|
2563
|
+
space: session.spaceId,
|
|
2564
|
+
entries,
|
|
2565
|
+
signal: request.signal,
|
|
2566
|
+
network: () => this.batchPutToNetwork(items, paths, request.signal, entries)
|
|
2567
|
+
});
|
|
2568
|
+
} catch (error) {
|
|
2569
|
+
const wrapped = wrapError("kv", error);
|
|
2570
|
+
return err({ ...wrapped, meta: { ...wrapped.meta, requestMayHaveDispatched: false } });
|
|
2571
|
+
} finally {
|
|
2572
|
+
request.dispose();
|
|
2573
|
+
}
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
async batchPutToNetwork(items, paths, signal, entries) {
|
|
2577
|
+
const session = this.context.session;
|
|
2578
|
+
let requestMayHaveDispatched = false;
|
|
2579
|
+
try {
|
|
2580
|
+
const body = new FormData();
|
|
2581
|
+
for (let index = 0; index < items.length; index++) {
|
|
2582
|
+
body.append(
|
|
2583
|
+
encodeKvBatchPartName(paths[index]),
|
|
2584
|
+
entries?.[index]?.body ?? this.serializeBatchPutValue(items[index])
|
|
2482
2585
|
);
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
return this.authorizationFailure(
|
|
2510
|
-
`Failed to batch put ${items.length} key(s)`,
|
|
2511
|
-
response,
|
|
2512
|
-
errorText,
|
|
2513
|
-
paths,
|
|
2514
|
-
KVAction.PUT
|
|
2515
|
-
);
|
|
2516
|
-
}
|
|
2517
|
-
const quotaError = this.handleQuotaErrorResponse(
|
|
2518
|
-
response,
|
|
2519
|
-
errorText,
|
|
2520
|
-
"batch"
|
|
2521
|
-
);
|
|
2522
|
-
if (quotaError) {
|
|
2523
|
-
return quotaError;
|
|
2524
|
-
}
|
|
2586
|
+
}
|
|
2587
|
+
const headers = this.context.invokeAny(
|
|
2588
|
+
session,
|
|
2589
|
+
paths.map((path) => ({
|
|
2590
|
+
spaceId: session.spaceId,
|
|
2591
|
+
service: "kv",
|
|
2592
|
+
path,
|
|
2593
|
+
action: KVAction.PUT
|
|
2594
|
+
}))
|
|
2595
|
+
);
|
|
2596
|
+
const url = `${this.host}/invoke`;
|
|
2597
|
+
const init = {
|
|
2598
|
+
method: "POST",
|
|
2599
|
+
headers,
|
|
2600
|
+
body,
|
|
2601
|
+
signal
|
|
2602
|
+
};
|
|
2603
|
+
const fetchFn = this.context.fetch;
|
|
2604
|
+
requestMayHaveDispatched = true;
|
|
2605
|
+
const response = await fetchFn(url, init);
|
|
2606
|
+
if (!response.ok) {
|
|
2607
|
+
let errorText;
|
|
2608
|
+
try {
|
|
2609
|
+
errorText = await response.text();
|
|
2610
|
+
} catch (textError) {
|
|
2611
|
+
const cause = textError instanceof Error ? textError : new Error(String(textError));
|
|
2525
2612
|
return err(
|
|
2526
2613
|
serviceError(
|
|
2527
2614
|
ErrorCodes.KV_WRITE_FAILED,
|
|
2528
|
-
`Failed to batch put ${items.length} key(s): ${response.status} - ${
|
|
2615
|
+
`Failed to batch put ${items.length} key(s): ${response.status} - <response body could not be read: ${cause.message}>`,
|
|
2529
2616
|
"kv",
|
|
2530
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2617
|
+
{ cause, meta: { status: response.status, statusText: response.statusText } }
|
|
2531
2618
|
)
|
|
2532
2619
|
);
|
|
2533
2620
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
serviceError(
|
|
2542
|
-
timedOut ? ErrorCodes.TIMEOUT : ErrorCodes.NETWORK_ERROR,
|
|
2543
|
-
timedOut ? `KV batchPut response body did not arrive in time: ${cause.message}` : `KV batchPut response was not valid JSON: ${cause.message}`,
|
|
2544
|
-
"kv",
|
|
2545
|
-
{
|
|
2546
|
-
cause,
|
|
2547
|
-
meta: {
|
|
2548
|
-
...timedOut ? { timeoutMs: cause.timeoutMs } : {},
|
|
2549
|
-
requestMayHaveDispatched: true,
|
|
2550
|
-
responseReceived: true,
|
|
2551
|
-
status: response.status,
|
|
2552
|
-
outcome: "batch-unconfirmed"
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
)
|
|
2621
|
+
if (response.status === 401 || response.status === 403) {
|
|
2622
|
+
return this.authorizationFailure(
|
|
2623
|
+
`Failed to batch put ${items.length} key(s)`,
|
|
2624
|
+
response,
|
|
2625
|
+
errorText,
|
|
2626
|
+
paths,
|
|
2627
|
+
KVAction.PUT
|
|
2556
2628
|
);
|
|
2557
2629
|
}
|
|
2558
|
-
const
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
{
|
|
2566
|
-
meta: {
|
|
2567
|
-
requestMayHaveDispatched: true,
|
|
2568
|
-
responseReceived: true,
|
|
2569
|
-
status: response.status,
|
|
2570
|
-
outcome: "batch-unconfirmed"
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
)
|
|
2574
|
-
);
|
|
2630
|
+
const quotaError = this.handleQuotaErrorResponse(
|
|
2631
|
+
response,
|
|
2632
|
+
errorText,
|
|
2633
|
+
"batch"
|
|
2634
|
+
);
|
|
2635
|
+
if (quotaError) {
|
|
2636
|
+
return quotaError;
|
|
2575
2637
|
}
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2638
|
+
return err(
|
|
2639
|
+
serviceError(
|
|
2640
|
+
ErrorCodes.KV_WRITE_FAILED,
|
|
2641
|
+
`Failed to batch put ${items.length} key(s): ${response.status} - ${errorText}`,
|
|
2642
|
+
"kv",
|
|
2643
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2644
|
+
)
|
|
2645
|
+
);
|
|
2646
|
+
}
|
|
2647
|
+
let rawBody;
|
|
2648
|
+
try {
|
|
2649
|
+
rawBody = await response.json();
|
|
2650
|
+
} catch (jsonError) {
|
|
2651
|
+
const cause = jsonError instanceof Error ? jsonError : new Error(String(jsonError));
|
|
2652
|
+
const timedOut = isRequestTimeoutError(cause);
|
|
2653
|
+
return err(
|
|
2654
|
+
serviceError(
|
|
2655
|
+
timedOut ? ErrorCodes.TIMEOUT : ErrorCodes.NETWORK_ERROR,
|
|
2656
|
+
timedOut ? `KV batchPut response body did not arrive in time: ${cause.message}` : `KV batchPut response was not valid JSON: ${cause.message}`,
|
|
2657
|
+
"kv",
|
|
2658
|
+
{
|
|
2659
|
+
cause,
|
|
2660
|
+
meta: {
|
|
2661
|
+
...timedOut ? { timeoutMs: cause.timeoutMs } : {},
|
|
2662
|
+
requestMayHaveDispatched: true,
|
|
2663
|
+
responseReceived: true,
|
|
2664
|
+
status: response.status,
|
|
2665
|
+
outcome: "batch-unconfirmed"
|
|
2592
2666
|
}
|
|
2593
|
-
|
|
2594
|
-
)
|
|
2595
|
-
|
|
2596
|
-
return ok(batchResponse);
|
|
2597
|
-
} catch (error) {
|
|
2598
|
-
const wrapped = wrapError("kv", error);
|
|
2599
|
-
return err({
|
|
2600
|
-
...wrapped,
|
|
2601
|
-
meta: { ...wrapped.meta, requestMayHaveDispatched }
|
|
2602
|
-
});
|
|
2603
|
-
} finally {
|
|
2604
|
-
request.dispose();
|
|
2667
|
+
}
|
|
2668
|
+
)
|
|
2669
|
+
);
|
|
2605
2670
|
}
|
|
2606
|
-
|
|
2671
|
+
const batchResponse = this.normalizeBatchPutResponse(rawBody);
|
|
2672
|
+
if (!batchResponse) {
|
|
2673
|
+
return err(
|
|
2674
|
+
serviceError(
|
|
2675
|
+
ErrorCodes.NETWORK_ERROR,
|
|
2676
|
+
"KV batchPut response did not include matching written keys and count",
|
|
2677
|
+
"kv",
|
|
2678
|
+
{
|
|
2679
|
+
meta: {
|
|
2680
|
+
requestMayHaveDispatched: true,
|
|
2681
|
+
responseReceived: true,
|
|
2682
|
+
status: response.status,
|
|
2683
|
+
outcome: "batch-unconfirmed"
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
)
|
|
2687
|
+
);
|
|
2688
|
+
}
|
|
2689
|
+
const requestedPaths = new Set(paths);
|
|
2690
|
+
const writtenPaths = new Set(batchResponse.written);
|
|
2691
|
+
const matchesRequest = batchResponse.count === paths.length && batchResponse.written.length === paths.length && writtenPaths.size === paths.length && batchResponse.written.every((key) => requestedPaths.has(key));
|
|
2692
|
+
if (!matchesRequest) {
|
|
2693
|
+
return err(
|
|
2694
|
+
serviceError(
|
|
2695
|
+
ErrorCodes.NETWORK_ERROR,
|
|
2696
|
+
`KV batchPut response did not confirm all ${paths.length} requested key(s) were written`,
|
|
2697
|
+
"kv",
|
|
2698
|
+
{
|
|
2699
|
+
meta: {
|
|
2700
|
+
requestMayHaveDispatched: true,
|
|
2701
|
+
responseReceived: true,
|
|
2702
|
+
status: response.status,
|
|
2703
|
+
outcome: "batch-unconfirmed"
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
)
|
|
2707
|
+
);
|
|
2708
|
+
}
|
|
2709
|
+
return ok(batchResponse);
|
|
2710
|
+
} catch (error) {
|
|
2711
|
+
const wrapped = wrapError("kv", error);
|
|
2712
|
+
return err({
|
|
2713
|
+
...wrapped,
|
|
2714
|
+
meta: { ...wrapped.meta, requestMayHaveDispatched }
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2607
2717
|
}
|
|
2608
2718
|
/**
|
|
2609
2719
|
* List keys with optional prefix filtering.
|
|
2610
2720
|
*/
|
|
2611
2721
|
async list(options) {
|
|
2612
2722
|
return this.withTelemetry("list", options?.prefix, async () => {
|
|
2723
|
+
if (this.readThroughReady !== null) await this.readThroughReady;
|
|
2613
2724
|
if (!this.requireAuth()) {
|
|
2614
2725
|
return err(authRequiredError("kv"));
|
|
2615
2726
|
}
|
|
@@ -2626,49 +2737,44 @@ var KVService = class extends BaseService {
|
|
|
2626
2737
|
}
|
|
2627
2738
|
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2628
2739
|
try {
|
|
2629
|
-
const
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2740
|
+
const network = () => this.listFromNetwork(listPath, options, request.signal);
|
|
2741
|
+
let page;
|
|
2742
|
+
if (options?.source === "network") {
|
|
2743
|
+
const observer = this.readThrough;
|
|
2744
|
+
if (observer === null) {
|
|
2745
|
+
page = await network();
|
|
2746
|
+
} else {
|
|
2747
|
+
let outcome = "error";
|
|
2748
|
+
const startedAt = Date.now();
|
|
2749
|
+
try {
|
|
2750
|
+
page = await network();
|
|
2751
|
+
outcome = page.ok ? "found" : "error";
|
|
2752
|
+
} finally {
|
|
2753
|
+
try {
|
|
2754
|
+
observer.observeNetworkRequested({
|
|
2755
|
+
op: "list",
|
|
2756
|
+
space: this.context.session.spaceId,
|
|
2757
|
+
path: listPath,
|
|
2758
|
+
reason: "NETWORK_REQUESTED",
|
|
2759
|
+
outcome,
|
|
2760
|
+
latencyMs: Date.now() - startedAt
|
|
2761
|
+
});
|
|
2762
|
+
} catch {
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2648
2765
|
}
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
let keys = await this.parseResponse(response, options?.raw);
|
|
2660
|
-
keys = keys ?? [];
|
|
2661
|
-
if (options?.removePrefix && listPath) {
|
|
2662
|
-
const prefixWithSlash = listPath.endsWith("/") ? listPath : `${listPath}/`;
|
|
2663
|
-
keys = keys.map(
|
|
2664
|
-
(key) => key.startsWith(prefixWithSlash) ? key.slice(prefixWithSlash.length) : key
|
|
2665
|
-
);
|
|
2766
|
+
} else if (this.readThrough === null) {
|
|
2767
|
+
page = await network();
|
|
2768
|
+
} else {
|
|
2769
|
+
page = await this.readThrough.list({
|
|
2770
|
+
space: this.context.session.spaceId,
|
|
2771
|
+
listPath,
|
|
2772
|
+
options,
|
|
2773
|
+
signal: request.signal,
|
|
2774
|
+
network
|
|
2775
|
+
});
|
|
2666
2776
|
}
|
|
2667
|
-
return ok(
|
|
2668
|
-
keys,
|
|
2669
|
-
...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" },
|
|
2670
|
-
...response.headers.get("x-tinycloud-next-cursor") === null ? {} : { nextCursor: response.headers.get("x-tinycloud-next-cursor") ?? void 0 }
|
|
2671
|
-
});
|
|
2777
|
+
return page.ok ? this.finishList(page.data, listPath, options?.removePrefix) : page;
|
|
2672
2778
|
} catch (error) {
|
|
2673
2779
|
return err(wrapError("kv", error));
|
|
2674
2780
|
} finally {
|
|
@@ -2676,6 +2782,56 @@ var KVService = class extends BaseService {
|
|
|
2676
2782
|
}
|
|
2677
2783
|
});
|
|
2678
2784
|
}
|
|
2785
|
+
async listFromNetwork(listPath, options, signal) {
|
|
2786
|
+
const response = await this.invokeOperation(
|
|
2787
|
+
listPath,
|
|
2788
|
+
KVAction.LIST,
|
|
2789
|
+
void 0,
|
|
2790
|
+
signal,
|
|
2791
|
+
options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
|
|
2792
|
+
...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
|
|
2793
|
+
...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
|
|
2794
|
+
}
|
|
2795
|
+
);
|
|
2796
|
+
if (!response.ok) {
|
|
2797
|
+
if (response.status === 401 || response.status === 403) {
|
|
2798
|
+
return this.authorizationFailure(
|
|
2799
|
+
"Failed to list keys",
|
|
2800
|
+
response,
|
|
2801
|
+
await this.readAuthorizationText(response),
|
|
2802
|
+
[listPath],
|
|
2803
|
+
KVAction.LIST
|
|
2804
|
+
);
|
|
2805
|
+
}
|
|
2806
|
+
const errorText = await response.text();
|
|
2807
|
+
return err(serviceError(
|
|
2808
|
+
ErrorCodes.NETWORK_ERROR,
|
|
2809
|
+
`Failed to list keys: ${response.status} - ${errorText}`,
|
|
2810
|
+
"kv",
|
|
2811
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2812
|
+
));
|
|
2813
|
+
}
|
|
2814
|
+
const keys = await this.parseResponse(response, options?.raw) ?? [];
|
|
2815
|
+
return ok({
|
|
2816
|
+
keys,
|
|
2817
|
+
...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" },
|
|
2818
|
+
...response.headers.get("x-tinycloud-next-cursor") === null ? {} : { nextCursor: response.headers.get("x-tinycloud-next-cursor") ?? void 0 }
|
|
2819
|
+
});
|
|
2820
|
+
}
|
|
2821
|
+
finishList(page, listPath, removePrefix) {
|
|
2822
|
+
let keys = page.keys;
|
|
2823
|
+
if (removePrefix && listPath) {
|
|
2824
|
+
const prefixWithSlash = listPath.endsWith("/") ? listPath : `${listPath}/`;
|
|
2825
|
+
keys = keys.map(
|
|
2826
|
+
(key) => key.startsWith(prefixWithSlash) ? key.slice(prefixWithSlash.length) : key
|
|
2827
|
+
);
|
|
2828
|
+
}
|
|
2829
|
+
return ok({
|
|
2830
|
+
keys,
|
|
2831
|
+
...page.truncated === void 0 ? {} : { truncated: page.truncated },
|
|
2832
|
+
...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor }
|
|
2833
|
+
});
|
|
2834
|
+
}
|
|
2679
2835
|
/**
|
|
2680
2836
|
* Read one page of the `tinycloud.kv/sync` change feed for a prefix.
|
|
2681
2837
|
*/
|
|
@@ -2698,6 +2854,7 @@ var KVService = class extends BaseService {
|
|
|
2698
2854
|
"kv"
|
|
2699
2855
|
));
|
|
2700
2856
|
}
|
|
2857
|
+
const requestPrefix = options.prefix === "/" ? "" : options.prefix;
|
|
2701
2858
|
const headers = {};
|
|
2702
2859
|
if (options.limit !== void 0) headers["x-tinycloud-limit"] = String(options.limit);
|
|
2703
2860
|
if (options.cursor !== void 0) headers["x-tinycloud-cursor"] = options.cursor;
|
|
@@ -2707,7 +2864,7 @@ var KVService = class extends BaseService {
|
|
|
2707
2864
|
const request = this.createRequestSignal(options.signal, options.timeout);
|
|
2708
2865
|
try {
|
|
2709
2866
|
const response = await this.invokeOperation(
|
|
2710
|
-
|
|
2867
|
+
requestPrefix,
|
|
2711
2868
|
KVAction.SYNC,
|
|
2712
2869
|
void 0,
|
|
2713
2870
|
request.signal,
|
|
@@ -2723,7 +2880,7 @@ var KVService = class extends BaseService {
|
|
|
2723
2880
|
} catch {
|
|
2724
2881
|
body = void 0;
|
|
2725
2882
|
}
|
|
2726
|
-
const page = this.normalizeChangesResponse(body);
|
|
2883
|
+
const page = this.normalizeChangesResponse(body, options.prefix);
|
|
2727
2884
|
if (!page) {
|
|
2728
2885
|
return err(serviceError(
|
|
2729
2886
|
ErrorCodes.NETWORK_ERROR,
|
|
@@ -2803,7 +2960,7 @@ var KVService = class extends BaseService {
|
|
|
2803
2960
|
{ meta }
|
|
2804
2961
|
));
|
|
2805
2962
|
}
|
|
2806
|
-
normalizeChangesResponse(data) {
|
|
2963
|
+
normalizeChangesResponse(data, requestedPrefix) {
|
|
2807
2964
|
if (!isJsonObject(data)) return void 0;
|
|
2808
2965
|
const { changes, more, cursor, source, authority } = data;
|
|
2809
2966
|
if (!Array.isArray(changes) || typeof more !== "boolean" || typeof cursor !== "string" || !isJsonObject(source) || typeof source.nodeDid !== "string" || typeof source.space !== "string" || typeof source.prefix !== "string" || !isJsonObject(authority)) {
|
|
@@ -2835,7 +2992,11 @@ var KVService = class extends BaseService {
|
|
|
2835
2992
|
changes: parsed,
|
|
2836
2993
|
more,
|
|
2837
2994
|
cursor,
|
|
2838
|
-
source: {
|
|
2995
|
+
source: {
|
|
2996
|
+
nodeDid: source.nodeDid,
|
|
2997
|
+
space: source.space,
|
|
2998
|
+
prefix: requestedPrefix === "/" && source.prefix === "" ? "/" : source.prefix
|
|
2999
|
+
},
|
|
2839
3000
|
authority: { notBefore, expiresAt, retainUntil }
|
|
2840
3001
|
};
|
|
2841
3002
|
}
|
|
@@ -2844,61 +3005,22 @@ var KVService = class extends BaseService {
|
|
|
2844
3005
|
*/
|
|
2845
3006
|
async delete(key, options) {
|
|
2846
3007
|
return this.withTelemetry("delete", key, async () => {
|
|
3008
|
+
if (this.readThroughReady !== null) await this.readThroughReady;
|
|
2847
3009
|
if (!this.requireAuth()) {
|
|
2848
3010
|
return err(authRequiredError("kv"));
|
|
2849
3011
|
}
|
|
2850
3012
|
const path = this.getFullPath(key, options?.prefix);
|
|
2851
3013
|
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2852
3014
|
try {
|
|
2853
|
-
const
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
return this.authorizationFailure(
|
|
2863
|
-
`Failed to delete key ${JSON.stringify(key)}`,
|
|
2864
|
-
response,
|
|
2865
|
-
await this.readAuthorizationText(response),
|
|
2866
|
-
[path],
|
|
2867
|
-
KVAction.DELETE
|
|
2868
|
-
);
|
|
2869
|
-
}
|
|
2870
|
-
if (response.status === 404) {
|
|
2871
|
-
return await this.classifyNotFound(response, key);
|
|
2872
|
-
}
|
|
2873
|
-
const errorText = await response.text();
|
|
2874
|
-
if (response.status === 412) {
|
|
2875
|
-
return err(serviceError(
|
|
2876
|
-
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
2877
|
-
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
2878
|
-
"kv",
|
|
2879
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2880
|
-
));
|
|
2881
|
-
}
|
|
2882
|
-
if (response.status === 503 && options?.ifMatch !== void 0) {
|
|
2883
|
-
return err(serviceError(
|
|
2884
|
-
ErrorCodes.KV_CONFLICT,
|
|
2885
|
-
`Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
|
|
2886
|
-
"kv",
|
|
2887
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2888
|
-
));
|
|
2889
|
-
}
|
|
2890
|
-
return err(
|
|
2891
|
-
serviceError(
|
|
2892
|
-
ErrorCodes.NETWORK_ERROR,
|
|
2893
|
-
`Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2894
|
-
"kv",
|
|
2895
|
-
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2896
|
-
)
|
|
2897
|
-
);
|
|
2898
|
-
}
|
|
2899
|
-
return ok({
|
|
2900
|
-
data: void 0,
|
|
2901
|
-
headers: this.createResponseHeaders(response.headers)
|
|
3015
|
+
const network = () => this.deleteFromNetwork(key, path, options, request.signal);
|
|
3016
|
+
if (this.readThrough === null) return await network();
|
|
3017
|
+
return await this.readThrough.write({
|
|
3018
|
+
op: "delete",
|
|
3019
|
+
space: this.context.session.spaceId,
|
|
3020
|
+
entries: [{ path }],
|
|
3021
|
+
signal: request.signal,
|
|
3022
|
+
conditional: options?.ifMatch !== void 0,
|
|
3023
|
+
network
|
|
2902
3024
|
});
|
|
2903
3025
|
} catch (error) {
|
|
2904
3026
|
return err(wrapError("kv", error));
|
|
@@ -2907,6 +3029,54 @@ var KVService = class extends BaseService {
|
|
|
2907
3029
|
}
|
|
2908
3030
|
});
|
|
2909
3031
|
}
|
|
3032
|
+
async deleteFromNetwork(key, path, options, signal) {
|
|
3033
|
+
const response = await this.invokeOperation(
|
|
3034
|
+
path,
|
|
3035
|
+
KVAction.DELETE,
|
|
3036
|
+
void 0,
|
|
3037
|
+
signal,
|
|
3038
|
+
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
3039
|
+
);
|
|
3040
|
+
if (!response.ok) {
|
|
3041
|
+
if (response.status === 401 || response.status === 403) {
|
|
3042
|
+
return this.authorizationFailure(
|
|
3043
|
+
`Failed to delete key ${JSON.stringify(key)}`,
|
|
3044
|
+
response,
|
|
3045
|
+
await this.readAuthorizationText(response),
|
|
3046
|
+
[path],
|
|
3047
|
+
KVAction.DELETE
|
|
3048
|
+
);
|
|
3049
|
+
}
|
|
3050
|
+
if (response.status === 404) return this.classifyNotFound(response, key);
|
|
3051
|
+
const errorText = await response.text();
|
|
3052
|
+
if (response.status === 412) {
|
|
3053
|
+
return err(serviceError(
|
|
3054
|
+
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
3055
|
+
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
3056
|
+
"kv",
|
|
3057
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3058
|
+
));
|
|
3059
|
+
}
|
|
3060
|
+
if (response.status === 503 && options?.ifMatch !== void 0) {
|
|
3061
|
+
return err(serviceError(
|
|
3062
|
+
ErrorCodes.KV_CONFLICT,
|
|
3063
|
+
`Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
|
|
3064
|
+
"kv",
|
|
3065
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3066
|
+
));
|
|
3067
|
+
}
|
|
3068
|
+
return err(serviceError(
|
|
3069
|
+
ErrorCodes.NETWORK_ERROR,
|
|
3070
|
+
`Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
3071
|
+
"kv",
|
|
3072
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3073
|
+
));
|
|
3074
|
+
}
|
|
3075
|
+
return ok({
|
|
3076
|
+
data: void 0,
|
|
3077
|
+
headers: this.createResponseHeaders(response.headers)
|
|
3078
|
+
});
|
|
3079
|
+
}
|
|
2910
3080
|
/**
|
|
2911
3081
|
* Get metadata for a key without retrieving the value.
|
|
2912
3082
|
*/
|
|
@@ -3074,6 +3244,65 @@ var KVService = class extends BaseService {
|
|
|
3074
3244
|
*/
|
|
3075
3245
|
KVService.serviceName = "kv";
|
|
3076
3246
|
|
|
3247
|
+
// src/kv/replication/constants.ts
|
|
3248
|
+
var CLEAR_PENDING_WARNING = "Clearing pending writes surrenders read-your-writes protection for the cleared keys. If a write whose record was cleared had an unknown outcome or never finished, it may commit now or later; this device can serve an older value until the next sync after that commit, as it would for a write from another device.";
|
|
3249
|
+
|
|
3250
|
+
// src/kv/replication/identity.ts
|
|
3251
|
+
var SPACE_ID = /^(tinycloud:pkh:eip155:\d+:)([^:]+)(:.+)$/;
|
|
3252
|
+
var PRINCIPAL_DID = /^(did:pkh:eip155:\d+:)([^:]+)$/;
|
|
3253
|
+
function canonicalReplicationIdentity(raw) {
|
|
3254
|
+
if (!raw || typeof raw.host !== "string" || typeof raw.space !== "string" || typeof raw.principal !== "string") {
|
|
3255
|
+
throw new TypeError(
|
|
3256
|
+
"Replication identity host, space, and principal must be strings"
|
|
3257
|
+
);
|
|
3258
|
+
}
|
|
3259
|
+
const authority = /^https?:\/\/([^/?#]*)/i.exec(raw.host)?.[1];
|
|
3260
|
+
let url;
|
|
3261
|
+
try {
|
|
3262
|
+
url = new URL(raw.host);
|
|
3263
|
+
} catch {
|
|
3264
|
+
throw new TypeError(
|
|
3265
|
+
"Replication identity host must be an absolute HTTP(S) URL"
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
if (!authority || authority.includes("@") || raw.host.includes("?") || raw.host.includes("#") || url.username || url.password) {
|
|
3269
|
+
throw new TypeError(
|
|
3270
|
+
"Replication identity host must be HTTP(S) without credentials, query, or fragment"
|
|
3271
|
+
);
|
|
3272
|
+
}
|
|
3273
|
+
const space = SPACE_ID.exec(raw.space);
|
|
3274
|
+
const principal = PRINCIPAL_DID.exec(raw.principal);
|
|
3275
|
+
if (!space || !principal) {
|
|
3276
|
+
throw new TypeError(
|
|
3277
|
+
"Replication identity requires a full TinyCloud space id and a pkh principal DID"
|
|
3278
|
+
);
|
|
3279
|
+
}
|
|
3280
|
+
return {
|
|
3281
|
+
host: `${url.origin}${url.pathname.replace(/\/+$/, "")}`,
|
|
3282
|
+
space: `${space[1]}${space[2].toLowerCase()}${space[3]}`,
|
|
3283
|
+
principal: `${principal[1]}${principal[2].toLowerCase()}`
|
|
3284
|
+
};
|
|
3285
|
+
}
|
|
3286
|
+
function replicationIdentityKey(id) {
|
|
3287
|
+
const canonical = canonicalReplicationIdentity(id);
|
|
3288
|
+
return `tc-replication/v1
|
|
3289
|
+
${canonical.host}
|
|
3290
|
+
${canonical.space}
|
|
3291
|
+
${canonical.principal}`;
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
// src/kv/replication/prefix.ts
|
|
3295
|
+
function kvPrefixCovers(prefix, key) {
|
|
3296
|
+
return prefix === "/" || key.startsWith(prefix);
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
// src/kv/replication/scope.ts
|
|
3300
|
+
function requiresSecretsOptIn(space, prefix) {
|
|
3301
|
+
if (prefix === "/") return true;
|
|
3302
|
+
if (space === "secrets" || space.endsWith(":secrets")) return true;
|
|
3303
|
+
return prefix.split("/", 1)[0] === "vault";
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3077
3306
|
// src/responseErrors.ts
|
|
3078
3307
|
function parseServiceErrorBody(errorText) {
|
|
3079
3308
|
try {
|
|
@@ -3250,7 +3479,7 @@ var SQLService = class extends BaseService {
|
|
|
3250
3479
|
request.signal
|
|
3251
3480
|
);
|
|
3252
3481
|
if (!response.ok) {
|
|
3253
|
-
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
3482
|
+
return await this.handleErrorResponse(response, "query", dbName, [action]);
|
|
3254
3483
|
}
|
|
3255
3484
|
const data = await response.json();
|
|
3256
3485
|
return ok(data);
|
|
@@ -3290,7 +3519,7 @@ var SQLService = class extends BaseService {
|
|
|
3290
3519
|
request.signal
|
|
3291
3520
|
);
|
|
3292
3521
|
if (!response.ok) {
|
|
3293
|
-
return this.handleErrorResponse(response, "execute", dbName, requestedActions);
|
|
3522
|
+
return await this.handleErrorResponse(response, "execute", dbName, requestedActions);
|
|
3294
3523
|
}
|
|
3295
3524
|
const data = await response.json();
|
|
3296
3525
|
return ok(data);
|
|
@@ -3316,7 +3545,7 @@ var SQLService = class extends BaseService {
|
|
|
3316
3545
|
request.signal
|
|
3317
3546
|
);
|
|
3318
3547
|
if (!response.ok) {
|
|
3319
|
-
return this.handleErrorResponse(response, "batch", dbName, requestedActions);
|
|
3548
|
+
return await this.handleErrorResponse(response, "batch", dbName, requestedActions);
|
|
3320
3549
|
}
|
|
3321
3550
|
const data = await response.json();
|
|
3322
3551
|
return ok(data);
|
|
@@ -3341,7 +3570,7 @@ var SQLService = class extends BaseService {
|
|
|
3341
3570
|
request.signal
|
|
3342
3571
|
);
|
|
3343
3572
|
if (!response.ok) {
|
|
3344
|
-
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
3573
|
+
return await this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
3345
3574
|
}
|
|
3346
3575
|
const data = await response.json();
|
|
3347
3576
|
return ok(data);
|
|
@@ -3366,7 +3595,7 @@ var SQLService = class extends BaseService {
|
|
|
3366
3595
|
request.signal
|
|
3367
3596
|
);
|
|
3368
3597
|
if (!response.ok) {
|
|
3369
|
-
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
3598
|
+
return await this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
3370
3599
|
}
|
|
3371
3600
|
const resp = response;
|
|
3372
3601
|
if (typeof resp.blob === "function") {
|
|
@@ -3742,7 +3971,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3742
3971
|
request.signal
|
|
3743
3972
|
);
|
|
3744
3973
|
if (!response.ok) {
|
|
3745
|
-
return this.handleErrorResponse(response, "query");
|
|
3974
|
+
return await this.handleErrorResponse(response, "query");
|
|
3746
3975
|
}
|
|
3747
3976
|
const data = await response.json();
|
|
3748
3977
|
return ok(data);
|
|
@@ -3768,7 +3997,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3768
3997
|
{ Accept: "application/vnd.apache.arrow.stream" }
|
|
3769
3998
|
);
|
|
3770
3999
|
if (!response.ok) {
|
|
3771
|
-
return this.handleErrorResponse(response, "queryArrow");
|
|
4000
|
+
return await this.handleErrorResponse(response, "queryArrow");
|
|
3772
4001
|
}
|
|
3773
4002
|
const buffer = await response.arrayBuffer();
|
|
3774
4003
|
return ok(buffer);
|
|
@@ -3801,7 +4030,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3801
4030
|
request.signal
|
|
3802
4031
|
);
|
|
3803
4032
|
if (!response.ok) {
|
|
3804
|
-
return this.handleErrorResponse(response, "execute");
|
|
4033
|
+
return await this.handleErrorResponse(response, "execute");
|
|
3805
4034
|
}
|
|
3806
4035
|
const data = await response.json();
|
|
3807
4036
|
return ok(data);
|
|
@@ -3833,7 +4062,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3833
4062
|
request.signal
|
|
3834
4063
|
);
|
|
3835
4064
|
if (!response.ok) {
|
|
3836
|
-
return this.handleErrorResponse(response, "batch");
|
|
4065
|
+
return await this.handleErrorResponse(response, "batch");
|
|
3837
4066
|
}
|
|
3838
4067
|
const data = await response.json();
|
|
3839
4068
|
return ok(data);
|
|
@@ -3858,7 +4087,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3858
4087
|
request.signal
|
|
3859
4088
|
);
|
|
3860
4089
|
if (!response.ok) {
|
|
3861
|
-
return this.handleErrorResponse(response, "executeStatement");
|
|
4090
|
+
return await this.handleErrorResponse(response, "executeStatement");
|
|
3862
4091
|
}
|
|
3863
4092
|
const data = await response.json();
|
|
3864
4093
|
return ok(data);
|
|
@@ -3883,7 +4112,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3883
4112
|
request.signal
|
|
3884
4113
|
);
|
|
3885
4114
|
if (!response.ok) {
|
|
3886
|
-
return this.handleErrorResponse(response, "describe");
|
|
4115
|
+
return await this.handleErrorResponse(response, "describe");
|
|
3887
4116
|
}
|
|
3888
4117
|
const data = await response.json();
|
|
3889
4118
|
return ok(data);
|
|
@@ -3908,7 +4137,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3908
4137
|
request.signal
|
|
3909
4138
|
);
|
|
3910
4139
|
if (!response.ok) {
|
|
3911
|
-
return this.handleErrorResponse(response, "export");
|
|
4140
|
+
return await this.handleErrorResponse(response, "export");
|
|
3912
4141
|
}
|
|
3913
4142
|
const blob = await response.blob();
|
|
3914
4143
|
return ok(blob);
|
|
@@ -3943,7 +4172,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3943
4172
|
signal: request.signal
|
|
3944
4173
|
});
|
|
3945
4174
|
if (!response.ok) {
|
|
3946
|
-
return this.handleErrorResponse(response, "import");
|
|
4175
|
+
return await this.handleErrorResponse(response, "import");
|
|
3947
4176
|
}
|
|
3948
4177
|
return ok(void 0);
|
|
3949
4178
|
} catch (error) {
|
|
@@ -5655,7 +5884,8 @@ var DataVaultService = class extends BaseService {
|
|
|
5655
5884
|
}
|
|
5656
5885
|
try {
|
|
5657
5886
|
const valueResult = await this.tc.kv.get(`vault/${key}`, {
|
|
5658
|
-
raw: true
|
|
5887
|
+
raw: true,
|
|
5888
|
+
...options?.source === void 0 ? {} : { source: options.source }
|
|
5659
5889
|
});
|
|
5660
5890
|
if (!valueResult.ok) {
|
|
5661
5891
|
return vaultError({ code: "KEY_NOT_FOUND", key });
|
|
@@ -5700,7 +5930,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5700
5930
|
}
|
|
5701
5931
|
let valueResult;
|
|
5702
5932
|
try {
|
|
5703
|
-
valueResult = await this.tc.kv.get(`vault/${key}`, { raw: true });
|
|
5933
|
+
valueResult = await this.tc.kv.get(`vault/${key}`, { raw: true, source: "network" });
|
|
5704
5934
|
} catch {
|
|
5705
5935
|
return { status: "node_unreachable" };
|
|
5706
5936
|
}
|
|
@@ -5769,7 +5999,8 @@ var DataVaultService = class extends BaseService {
|
|
|
5769
5999
|
}
|
|
5770
6000
|
try {
|
|
5771
6001
|
const valueResult = await this.tc.kv.get(`vault/${key}`, {
|
|
5772
|
-
raw: true
|
|
6002
|
+
raw: true,
|
|
6003
|
+
source: "network"
|
|
5773
6004
|
});
|
|
5774
6005
|
if (!valueResult.ok) {
|
|
5775
6006
|
return vaultError({ code: "KEY_NOT_FOUND", key });
|
|
@@ -5903,7 +6134,8 @@ var DataVaultService = class extends BaseService {
|
|
|
5903
6134
|
}
|
|
5904
6135
|
try {
|
|
5905
6136
|
const keyResult = await this.tc.kv.get(`keys/${key}`, {
|
|
5906
|
-
raw: true
|
|
6137
|
+
raw: true,
|
|
6138
|
+
...options?.source === void 0 ? {} : { source: options.source }
|
|
5907
6139
|
});
|
|
5908
6140
|
if (!keyResult.ok) {
|
|
5909
6141
|
return vaultError({ code: "KEY_NOT_FOUND", key });
|
|
@@ -5912,7 +6144,8 @@ var DataVaultService = class extends BaseService {
|
|
|
5912
6144
|
const keyBlobBytes = base64Decode(keyEnvelope.key);
|
|
5913
6145
|
const entryKey = this.crypto.decrypt(this.masterKey, keyBlobBytes);
|
|
5914
6146
|
const valueResult = await this.tc.kv.get(`vault/${key}`, {
|
|
5915
|
-
raw: true
|
|
6147
|
+
raw: true,
|
|
6148
|
+
...options?.source === void 0 ? {} : { source: options.source }
|
|
5916
6149
|
});
|
|
5917
6150
|
if (!valueResult.ok) {
|
|
5918
6151
|
return vaultError({ code: "KEY_NOT_FOUND", key });
|
|
@@ -6022,6 +6255,7 @@ var DataVaultService = class extends BaseService {
|
|
|
6022
6255
|
prefix: listPrefix,
|
|
6023
6256
|
removePrefix: true,
|
|
6024
6257
|
...options?.limit === void 0 ? {} : { limit: options.limit },
|
|
6258
|
+
...options?.source === void 0 ? {} : { source: options.source },
|
|
6025
6259
|
...options?.cursor === void 0 ? {} : { cursor: options.cursor }
|
|
6026
6260
|
});
|
|
6027
6261
|
if (!listResult.ok) {
|
|
@@ -6746,7 +6980,9 @@ var SecretsService = class {
|
|
|
6746
6980
|
async get(name, options) {
|
|
6747
6981
|
const secretPath = resolveSecretPathResult(name, options);
|
|
6748
6982
|
if ("ok" in secretPath) return secretPath;
|
|
6749
|
-
const result = await this.vault.get(secretPath.vaultKey)
|
|
6983
|
+
const result = options?.source === void 0 ? await this.vault.get(secretPath.vaultKey) : await this.vault.get(secretPath.vaultKey, {
|
|
6984
|
+
source: options.source
|
|
6985
|
+
});
|
|
6750
6986
|
if (!result.ok) {
|
|
6751
6987
|
return result;
|
|
6752
6988
|
}
|
|
@@ -6780,7 +7016,8 @@ var SecretsService = class {
|
|
|
6780
7016
|
}
|
|
6781
7017
|
const result = await this.vault.list({
|
|
6782
7018
|
prefix,
|
|
6783
|
-
removePrefix: true
|
|
7019
|
+
removePrefix: true,
|
|
7020
|
+
...options?.source === void 0 ? {} : { source: options.source }
|
|
6784
7021
|
});
|
|
6785
7022
|
if (!result.ok) {
|
|
6786
7023
|
return result;
|
|
@@ -6799,6 +7036,7 @@ var SecretsService = class {
|
|
|
6799
7036
|
prefix: "secrets/",
|
|
6800
7037
|
removePrefix: true,
|
|
6801
7038
|
limit: 1e3,
|
|
7039
|
+
source: "network",
|
|
6802
7040
|
...cursor === void 0 ? {} : { cursor }
|
|
6803
7041
|
});
|
|
6804
7042
|
if (!result.ok) {
|
|
@@ -7790,6 +8028,7 @@ EncryptionService.serviceName = "encryption";
|
|
|
7790
8028
|
import { DecryptTransportResponseError as DecryptTransportResponseError3 } from "@tinycloud/sdk-services/internal/decrypt-transport-response-error";
|
|
7791
8029
|
export {
|
|
7792
8030
|
BaseService,
|
|
8031
|
+
CLEAR_PENDING_WARNING,
|
|
7793
8032
|
DECRYPT_ACTION,
|
|
7794
8033
|
DECRYPT_FACT_TYPE,
|
|
7795
8034
|
DECRYPT_RESULT_TYPE,
|
|
@@ -7857,6 +8096,7 @@ export {
|
|
|
7857
8096
|
buildDecryptInvocation,
|
|
7858
8097
|
buildNetworkId,
|
|
7859
8098
|
canonicalHashHex,
|
|
8099
|
+
canonicalReplicationIdentity,
|
|
7860
8100
|
canonicalSignedResponse,
|
|
7861
8101
|
canonicalize as canonicalizeEncryptionJson,
|
|
7862
8102
|
canonicalizeSecretScope,
|
|
@@ -7883,6 +8123,7 @@ export {
|
|
|
7883
8123
|
installTinyCloudDebugGlobals,
|
|
7884
8124
|
isNetworkId,
|
|
7885
8125
|
isStorageFullError,
|
|
8126
|
+
kvPrefixCovers,
|
|
7886
8127
|
networkDiscoveryKey,
|
|
7887
8128
|
networkError,
|
|
7888
8129
|
notFoundError,
|
|
@@ -7896,6 +8137,8 @@ export {
|
|
|
7896
8137
|
parseSecretCatalogKey,
|
|
7897
8138
|
parseStorageQuotaBytes,
|
|
7898
8139
|
permissionDeniedError,
|
|
8140
|
+
replicationIdentityKey,
|
|
8141
|
+
requiresSecretsOptIn,
|
|
7899
8142
|
resolveSecretListPrefix,
|
|
7900
8143
|
resolveSecretPath,
|
|
7901
8144
|
serviceError,
|