@tinycloud/operations 0.1.0 → 0.2.0-beta.0
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/artifacts.cjs +100 -10
- package/dist/artifacts.cjs.map +1 -1
- package/dist/artifacts.d.cts +1 -1
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +100 -10
- package/dist/artifacts.js.map +1 -1
- package/dist/cli-runtime.cjs +1102 -113
- package/dist/cli-runtime.cjs.map +1 -1
- package/dist/cli-runtime.d.cts +1 -1
- package/dist/cli-runtime.d.ts +1 -1
- package/dist/cli-runtime.js +1101 -112
- package/dist/cli-runtime.js.map +1 -1
- package/dist/{contract-mCY8LFFI.d.cts → contract-OnWT3OXa.d.cts} +1 -1
- package/dist/{contract-mCY8LFFI.d.ts → contract-OnWT3OXa.d.ts} +1 -1
- package/dist/index.cjs +1099 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1098 -109
- package/dist/index.js.map +1 -1
- package/dist/profile.d.cts +1 -1
- package/dist/profile.d.ts +1 -1
- package/generated/operations.json +6348 -176
- package/package.json +4 -3
package/dist/cli-runtime.cjs
CHANGED
|
@@ -88,6 +88,14 @@ var init_errors = __esm({
|
|
|
88
88
|
"ENCRYPTION_NETWORK_UNRESOLVED",
|
|
89
89
|
"NODE_UNREACHABLE",
|
|
90
90
|
"NODE_ERROR",
|
|
91
|
+
"KV_NOT_FOUND",
|
|
92
|
+
"KV_PRECONDITION_FAILED",
|
|
93
|
+
"KV_CONFLICT",
|
|
94
|
+
"KV_RESPONSE_TOO_LARGE",
|
|
95
|
+
"SQL_QUERY_INVALID",
|
|
96
|
+
"SQL_EXECUTION_FAILED",
|
|
97
|
+
"SQL_RESULT_LIMIT_EXCEEDED",
|
|
98
|
+
"SQL_VALUE_UNSAFE",
|
|
91
99
|
"SECRET_READ_FAILED",
|
|
92
100
|
"SECRET_DECRYPT_FAILED",
|
|
93
101
|
"OUTPUT_INVALID",
|
|
@@ -1135,6 +1143,11 @@ function validateMigrationOptions(options) {
|
|
|
1135
1143
|
}
|
|
1136
1144
|
return null;
|
|
1137
1145
|
}
|
|
1146
|
+
function serializeSqlValues(values) {
|
|
1147
|
+
return values.map(
|
|
1148
|
+
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1138
1151
|
function migrationKey(namespace, id) {
|
|
1139
1152
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
1140
1153
|
}
|
|
@@ -2408,6 +2421,9 @@ var init_dist2 = __esm({
|
|
|
2408
2421
|
// KV-specific errors
|
|
2409
2422
|
KV_NOT_FOUND: "KV_NOT_FOUND",
|
|
2410
2423
|
KV_WRITE_FAILED: "KV_WRITE_FAILED",
|
|
2424
|
+
KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
|
|
2425
|
+
KV_CONFLICT: "KV_CONFLICT",
|
|
2426
|
+
KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
|
|
2411
2427
|
// SQL-specific errors
|
|
2412
2428
|
SQL_ERROR: "SQL_ERROR",
|
|
2413
2429
|
SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
|
|
@@ -3085,7 +3101,7 @@ var init_dist2 = __esm({
|
|
|
3085
3101
|
* @param signal - Optional abort signal
|
|
3086
3102
|
* @returns Fetch response
|
|
3087
3103
|
*/
|
|
3088
|
-
async invokeOperation(path, action, body, signal) {
|
|
3104
|
+
async invokeOperation(path, action, body, signal, extraHeaders) {
|
|
3089
3105
|
const session = this.context.session;
|
|
3090
3106
|
const headers = this.context.invoke(
|
|
3091
3107
|
session,
|
|
@@ -3093,9 +3109,10 @@ var init_dist2 = __esm({
|
|
|
3093
3109
|
path,
|
|
3094
3110
|
action
|
|
3095
3111
|
);
|
|
3112
|
+
const requestHeaders = Array.isArray(headers) ? [...headers, ...Object.entries(extraHeaders ?? {})] : { ...headers, ...extraHeaders };
|
|
3096
3113
|
return this.context.fetch(`${this.host}/invoke`, {
|
|
3097
3114
|
method: "POST",
|
|
3098
|
-
headers,
|
|
3115
|
+
headers: requestHeaders,
|
|
3099
3116
|
body,
|
|
3100
3117
|
signal: this.combineSignals(signal)
|
|
3101
3118
|
});
|
|
@@ -3277,13 +3294,21 @@ var init_dist2 = __esm({
|
|
|
3277
3294
|
if (!this.requireAuth()) {
|
|
3278
3295
|
return err(authRequiredError("kv"));
|
|
3279
3296
|
}
|
|
3297
|
+
if (options?.maxResponseBytes !== void 0 && (!Number.isSafeInteger(options.maxResponseBytes) || options.maxResponseBytes <= 0)) {
|
|
3298
|
+
return err(serviceError(
|
|
3299
|
+
ErrorCodes.INVALID_INPUT,
|
|
3300
|
+
"KV maxResponseBytes must be a positive safe integer",
|
|
3301
|
+
"kv"
|
|
3302
|
+
));
|
|
3303
|
+
}
|
|
3280
3304
|
const path = this.getFullPath(key, options?.prefix);
|
|
3281
3305
|
try {
|
|
3282
3306
|
const response = await this.invokeOperation(
|
|
3283
3307
|
path,
|
|
3284
3308
|
KVAction.GET,
|
|
3285
3309
|
void 0,
|
|
3286
|
-
options?.signal
|
|
3310
|
+
options?.signal,
|
|
3311
|
+
options?.maxResponseBytes === void 0 ? void 0 : { "x-tinycloud-max-response-bytes": String(options.maxResponseBytes) }
|
|
3287
3312
|
);
|
|
3288
3313
|
if (!response.ok) {
|
|
3289
3314
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -3301,6 +3326,14 @@ var init_dist2 = __esm({
|
|
|
3301
3326
|
return this.classifyNotFound(response, key);
|
|
3302
3327
|
}
|
|
3303
3328
|
const errorText = await response.text();
|
|
3329
|
+
if (response.status === 413) {
|
|
3330
|
+
return err(serviceError(
|
|
3331
|
+
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
3332
|
+
`KV value at key "${key}" exceeds the requested response limit`,
|
|
3333
|
+
"kv",
|
|
3334
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3335
|
+
));
|
|
3336
|
+
}
|
|
3304
3337
|
return err(
|
|
3305
3338
|
serviceError(
|
|
3306
3339
|
ErrorCodes.NETWORK_ERROR,
|
|
@@ -3332,6 +3365,13 @@ var init_dist2 = __esm({
|
|
|
3332
3365
|
if (!this.requireAuth()) {
|
|
3333
3366
|
return err(authRequiredError("kv"));
|
|
3334
3367
|
}
|
|
3368
|
+
if (options?.ifMatch !== void 0 && options.ifNoneMatch !== void 0) {
|
|
3369
|
+
return err(serviceError(
|
|
3370
|
+
ErrorCodes.INVALID_INPUT,
|
|
3371
|
+
"KV put cannot combine ifMatch and ifNoneMatch",
|
|
3372
|
+
"kv"
|
|
3373
|
+
));
|
|
3374
|
+
}
|
|
3335
3375
|
const path = this.getFullPath(key, options?.prefix);
|
|
3336
3376
|
const body = this.serializePutValue(value, options?.contentType);
|
|
3337
3377
|
try {
|
|
@@ -3339,7 +3379,11 @@ var init_dist2 = __esm({
|
|
|
3339
3379
|
path,
|
|
3340
3380
|
KVAction.PUT,
|
|
3341
3381
|
body,
|
|
3342
|
-
options?.signal
|
|
3382
|
+
options?.signal,
|
|
3383
|
+
{
|
|
3384
|
+
...options?.ifMatch === void 0 ? {} : { "if-match": options.ifMatch },
|
|
3385
|
+
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
3386
|
+
}
|
|
3343
3387
|
);
|
|
3344
3388
|
if (!response.ok) {
|
|
3345
3389
|
if (response.status === 401) {
|
|
@@ -3352,6 +3396,22 @@ var init_dist2 = __esm({
|
|
|
3352
3396
|
}));
|
|
3353
3397
|
}
|
|
3354
3398
|
const errorText = await response.text();
|
|
3399
|
+
if (response.status === 412) {
|
|
3400
|
+
return err(serviceError(
|
|
3401
|
+
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
3402
|
+
`KV precondition failed for key "${key}"`,
|
|
3403
|
+
"kv",
|
|
3404
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3405
|
+
));
|
|
3406
|
+
}
|
|
3407
|
+
if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
|
|
3408
|
+
return err(serviceError(
|
|
3409
|
+
ErrorCodes.KV_CONFLICT,
|
|
3410
|
+
`Concurrent KV update conflicted for key "${key}"`,
|
|
3411
|
+
"kv",
|
|
3412
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3413
|
+
));
|
|
3414
|
+
}
|
|
3355
3415
|
const quotaError = this.handleQuotaErrorResponse(
|
|
3356
3416
|
response,
|
|
3357
3417
|
errorText,
|
|
@@ -3487,6 +3547,13 @@ var init_dist2 = __esm({
|
|
|
3487
3547
|
if (!this.requireAuth()) {
|
|
3488
3548
|
return err(authRequiredError("kv"));
|
|
3489
3549
|
}
|
|
3550
|
+
if (options?.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 1e3)) {
|
|
3551
|
+
return err(serviceError(
|
|
3552
|
+
ErrorCodes.INVALID_INPUT,
|
|
3553
|
+
"KV list limit must be an integer from 1 through 1000",
|
|
3554
|
+
"kv"
|
|
3555
|
+
));
|
|
3556
|
+
}
|
|
3490
3557
|
let listPath = options?.prefix ?? this._config.prefix ?? "";
|
|
3491
3558
|
if (options?.path) {
|
|
3492
3559
|
listPath = listPath ? `${listPath}/${options.path}` : options.path;
|
|
@@ -3496,7 +3563,8 @@ var init_dist2 = __esm({
|
|
|
3496
3563
|
listPath,
|
|
3497
3564
|
KVAction.LIST,
|
|
3498
3565
|
void 0,
|
|
3499
|
-
options?.signal
|
|
3566
|
+
options?.signal,
|
|
3567
|
+
options?.limit === void 0 ? void 0 : { "x-tinycloud-limit": String(options.limit) }
|
|
3500
3568
|
);
|
|
3501
3569
|
if (!response.ok) {
|
|
3502
3570
|
if (response.status === 401) {
|
|
@@ -3526,7 +3594,10 @@ var init_dist2 = __esm({
|
|
|
3526
3594
|
(key) => key.startsWith(prefixWithSlash) ? key.slice(prefixWithSlash.length) : key
|
|
3527
3595
|
);
|
|
3528
3596
|
}
|
|
3529
|
-
return ok({
|
|
3597
|
+
return ok({
|
|
3598
|
+
keys,
|
|
3599
|
+
...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" }
|
|
3600
|
+
});
|
|
3530
3601
|
} catch (error) {
|
|
3531
3602
|
return err(wrapError("kv", error));
|
|
3532
3603
|
}
|
|
@@ -3546,7 +3617,8 @@ var init_dist2 = __esm({
|
|
|
3546
3617
|
path,
|
|
3547
3618
|
KVAction.DELETE,
|
|
3548
3619
|
void 0,
|
|
3549
|
-
options?.signal
|
|
3620
|
+
options?.signal,
|
|
3621
|
+
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
3550
3622
|
);
|
|
3551
3623
|
if (!response.ok) {
|
|
3552
3624
|
if (response.status === 401) {
|
|
@@ -3562,6 +3634,22 @@ var init_dist2 = __esm({
|
|
|
3562
3634
|
return this.classifyNotFound(response, key);
|
|
3563
3635
|
}
|
|
3564
3636
|
const errorText = await response.text();
|
|
3637
|
+
if (response.status === 412) {
|
|
3638
|
+
return err(serviceError(
|
|
3639
|
+
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
3640
|
+
`KV precondition failed for key "${key}"`,
|
|
3641
|
+
"kv",
|
|
3642
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3643
|
+
));
|
|
3644
|
+
}
|
|
3645
|
+
if (response.status === 503 && options?.ifMatch !== void 0) {
|
|
3646
|
+
return err(serviceError(
|
|
3647
|
+
ErrorCodes.KV_CONFLICT,
|
|
3648
|
+
`Concurrent KV delete conflicted for key "${key}"`,
|
|
3649
|
+
"kv",
|
|
3650
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3651
|
+
));
|
|
3652
|
+
}
|
|
3565
3653
|
return err(
|
|
3566
3654
|
serviceError(
|
|
3567
3655
|
ErrorCodes.NETWORK_ERROR,
|
|
@@ -3571,7 +3659,10 @@ var init_dist2 = __esm({
|
|
|
3571
3659
|
)
|
|
3572
3660
|
);
|
|
3573
3661
|
}
|
|
3574
|
-
return ok(
|
|
3662
|
+
return ok({
|
|
3663
|
+
data: void 0,
|
|
3664
|
+
headers: this.createResponseHeaders(response.headers)
|
|
3665
|
+
});
|
|
3575
3666
|
} catch (error) {
|
|
3576
3667
|
return err(wrapError("kv", error));
|
|
3577
3668
|
}
|
|
@@ -3843,10 +3934,17 @@ var init_dist2 = __esm({
|
|
|
3843
3934
|
return err(authRequiredError("sql"));
|
|
3844
3935
|
}
|
|
3845
3936
|
try {
|
|
3937
|
+
const body = {
|
|
3938
|
+
action: "query",
|
|
3939
|
+
sql,
|
|
3940
|
+
params: serializeSqlValues(params ?? [])
|
|
3941
|
+
};
|
|
3942
|
+
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
3943
|
+
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
3846
3944
|
const response = await this.invokeSQL(
|
|
3847
3945
|
dbName,
|
|
3848
3946
|
this.actionForSql(sql, SQLAction.READ),
|
|
3849
|
-
|
|
3947
|
+
body,
|
|
3850
3948
|
options?.signal
|
|
3851
3949
|
);
|
|
3852
3950
|
if (!response.ok) {
|
|
@@ -3868,7 +3966,7 @@ var init_dist2 = __esm({
|
|
|
3868
3966
|
const body = {
|
|
3869
3967
|
action: "execute",
|
|
3870
3968
|
sql,
|
|
3871
|
-
params: params ?? []
|
|
3969
|
+
params: serializeSqlValues(params ?? [])
|
|
3872
3970
|
};
|
|
3873
3971
|
if (options?.schema) {
|
|
3874
3972
|
body.schema = options.schema;
|
|
@@ -7820,7 +7918,7 @@ async function planAccountRegistryRead(context, path) {
|
|
|
7820
7918
|
}];
|
|
7821
7919
|
}
|
|
7822
7920
|
async function planKvList(context, input) {
|
|
7823
|
-
const space =
|
|
7921
|
+
const space = resolveGenericKvSpace(context, input.space);
|
|
7824
7922
|
return [{
|
|
7825
7923
|
service: "tinycloud.kv",
|
|
7826
7924
|
space,
|
|
@@ -7829,7 +7927,7 @@ async function planKvList(context, input) {
|
|
|
7829
7927
|
}];
|
|
7830
7928
|
}
|
|
7831
7929
|
async function planKvGet(context, input) {
|
|
7832
|
-
const space =
|
|
7930
|
+
const space = resolveGenericKvSpace(context, input.space);
|
|
7833
7931
|
return [{
|
|
7834
7932
|
service: "tinycloud.kv",
|
|
7835
7933
|
space,
|
|
@@ -7837,12 +7935,21 @@ async function planKvGet(context, input) {
|
|
|
7837
7935
|
actions: ["tinycloud.kv/get"]
|
|
7838
7936
|
}];
|
|
7839
7937
|
}
|
|
7938
|
+
async function planExactKv(context, requestedSpace, key, action) {
|
|
7939
|
+
return [{
|
|
7940
|
+
service: "tinycloud.kv",
|
|
7941
|
+
space: resolveGenericKvSpace(context, requestedSpace),
|
|
7942
|
+
path: key,
|
|
7943
|
+
actions: [action]
|
|
7944
|
+
}];
|
|
7945
|
+
}
|
|
7840
7946
|
async function executeAccountSpacesList(context, _input) {
|
|
7841
7947
|
try {
|
|
7842
7948
|
const entries = await readAccountRegistry(context, "spaces/");
|
|
7843
|
-
if (!entries.ok) return
|
|
7949
|
+
if (!entries.ok) return entries.outcome;
|
|
7844
7950
|
const spaces = entries.records.map(({ key, value }) => projectAccountSpace(key, value)).sort((left, right) => left.name.localeCompare(right.name) || left.spaceId.localeCompare(right.spaceId));
|
|
7845
|
-
|
|
7951
|
+
const output = { spaces, count: spaces.length };
|
|
7952
|
+
return accountRegistryOutput(output);
|
|
7846
7953
|
} catch {
|
|
7847
7954
|
return nodeFailure("list account spaces");
|
|
7848
7955
|
}
|
|
@@ -7850,9 +7957,10 @@ async function executeAccountSpacesList(context, _input) {
|
|
|
7850
7957
|
async function executeAccountApplicationsList(context, _input) {
|
|
7851
7958
|
try {
|
|
7852
7959
|
const entries = await readAccountRegistry(context, "applications/");
|
|
7853
|
-
if (!entries.ok) return
|
|
7960
|
+
if (!entries.ok) return entries.outcome;
|
|
7854
7961
|
const applications = entries.records.map(({ key, value }) => projectAccountApplication(key, value)).sort((left, right) => left.appId.localeCompare(right.appId));
|
|
7855
|
-
|
|
7962
|
+
const output = { applications, count: applications.length };
|
|
7963
|
+
return accountRegistryOutput(output);
|
|
7856
7964
|
} catch {
|
|
7857
7965
|
return nodeFailure("list account applications");
|
|
7858
7966
|
}
|
|
@@ -7860,15 +7968,22 @@ async function executeAccountApplicationsList(context, _input) {
|
|
|
7860
7968
|
async function executeKvList(context, input) {
|
|
7861
7969
|
try {
|
|
7862
7970
|
const runtime = runtimeContext(context);
|
|
7863
|
-
const space =
|
|
7864
|
-
const result = await
|
|
7865
|
-
input.prefix === void 0 ?
|
|
7866
|
-
|
|
7971
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
7972
|
+
const result = await genericKv(runtime, space).list({
|
|
7973
|
+
...input.prefix === void 0 ? {} : { prefix: input.prefix },
|
|
7974
|
+
limit: input.limit ?? DEFAULT_KV_LIST_LIMIT
|
|
7975
|
+
});
|
|
7867
7976
|
if (!result.ok) return nodeFailure("list KV keys");
|
|
7868
7977
|
const keys = [...result.data.keys];
|
|
7869
7978
|
return {
|
|
7870
7979
|
status: "ok",
|
|
7871
|
-
output: {
|
|
7980
|
+
output: {
|
|
7981
|
+
space,
|
|
7982
|
+
prefix: input.prefix ?? "",
|
|
7983
|
+
keys,
|
|
7984
|
+
count: keys.length,
|
|
7985
|
+
truncated: result.data.truncated ?? false
|
|
7986
|
+
}
|
|
7872
7987
|
};
|
|
7873
7988
|
} catch (error) {
|
|
7874
7989
|
if (error instanceof OperationInvocationError) {
|
|
@@ -7880,10 +7995,18 @@ async function executeKvList(context, input) {
|
|
|
7880
7995
|
async function executeKvGet(context, input) {
|
|
7881
7996
|
try {
|
|
7882
7997
|
const runtime = runtimeContext(context);
|
|
7883
|
-
const space =
|
|
7884
|
-
const result = await
|
|
7885
|
-
|
|
7886
|
-
|
|
7998
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
7999
|
+
const result = await genericKv(runtime, space).get(input.key, {
|
|
8000
|
+
binary: true,
|
|
8001
|
+
maxResponseBytes: MAX_KV_VALUE_BYTES
|
|
8002
|
+
});
|
|
8003
|
+
if (!result.ok) return kvFailure(result.error, "read the KV value");
|
|
8004
|
+
const bytes = result.data.data;
|
|
8005
|
+
if (bytes.byteLength > MAX_KV_VALUE_BYTES) {
|
|
8006
|
+
return kvFailure({ code: "KV_RESPONSE_TOO_LARGE" }, "read the KV value");
|
|
8007
|
+
}
|
|
8008
|
+
const encoded = encodeKvValue(bytes, input.representation ?? "base64");
|
|
8009
|
+
if (!encoded.ok) return encoded.outcome;
|
|
7887
8010
|
return {
|
|
7888
8011
|
status: "ok",
|
|
7889
8012
|
output: {
|
|
@@ -7891,12 +8014,8 @@ async function executeKvGet(context, input) {
|
|
|
7891
8014
|
key: input.key,
|
|
7892
8015
|
value: encoded.value,
|
|
7893
8016
|
encoding: encoded.encoding,
|
|
7894
|
-
metadata:
|
|
7895
|
-
|
|
7896
|
-
...result.data.headers.contentType === void 0 ? {} : { contentType: result.data.headers.contentType },
|
|
7897
|
-
...result.data.headers.lastModified === void 0 ? {} : { lastModified: result.data.headers.lastModified },
|
|
7898
|
-
...result.data.headers.contentLength === void 0 ? {} : { contentLength: result.data.headers.contentLength }
|
|
7899
|
-
}
|
|
8017
|
+
metadata: projectKvMetadata(result.data.headers),
|
|
8018
|
+
byteLength: bytes.byteLength
|
|
7900
8019
|
}
|
|
7901
8020
|
};
|
|
7902
8021
|
} catch (error) {
|
|
@@ -7906,6 +8025,66 @@ async function executeKvGet(context, input) {
|
|
|
7906
8025
|
return nodeFailure("read the KV value");
|
|
7907
8026
|
}
|
|
7908
8027
|
}
|
|
8028
|
+
async function executeKvHead(context, input) {
|
|
8029
|
+
try {
|
|
8030
|
+
const runtime = runtimeContext(context);
|
|
8031
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8032
|
+
const result = await genericKv(runtime, space).head(input.key);
|
|
8033
|
+
if (!result.ok) return kvFailure(result.error, "read KV metadata");
|
|
8034
|
+
return { status: "ok", output: { space, key: input.key, metadata: projectKvMetadata(result.data.headers) } };
|
|
8035
|
+
} catch (error) {
|
|
8036
|
+
return caughtKvFailure(error, "read KV metadata");
|
|
8037
|
+
}
|
|
8038
|
+
}
|
|
8039
|
+
async function executeKvPut(context, input) {
|
|
8040
|
+
try {
|
|
8041
|
+
const runtime = runtimeContext(context);
|
|
8042
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8043
|
+
const decoded = decodeKvPutContent(input.content);
|
|
8044
|
+
if (decoded === void 0 || decoded.byteLength > MAX_KV_VALUE_BYTES) {
|
|
8045
|
+
return { status: "error", error: operationError("INPUT_INVALID", "The KV content is invalid or too large.") };
|
|
8046
|
+
}
|
|
8047
|
+
const result = await genericKv(runtime, space).put(input.key, decoded.bytes, {
|
|
8048
|
+
contentType: input.contentType ?? decoded.contentType,
|
|
8049
|
+
...input.mode === "create" ? { ifNoneMatch: "*" } : {},
|
|
8050
|
+
...input.mode === "replace" ? { ifMatch: input.etag } : {}
|
|
8051
|
+
});
|
|
8052
|
+
if (!result.ok) return kvFailure(result.error, "write the KV value");
|
|
8053
|
+
return {
|
|
8054
|
+
status: "ok",
|
|
8055
|
+
output: {
|
|
8056
|
+
space,
|
|
8057
|
+
key: input.key,
|
|
8058
|
+
mode: input.mode,
|
|
8059
|
+
byteLength: decoded.byteLength,
|
|
8060
|
+
metadata: projectKvMetadata(result.data.headers)
|
|
8061
|
+
}
|
|
8062
|
+
};
|
|
8063
|
+
} catch (error) {
|
|
8064
|
+
return caughtKvFailure(error, "write the KV value");
|
|
8065
|
+
}
|
|
8066
|
+
}
|
|
8067
|
+
async function executeKvDelete(context, input) {
|
|
8068
|
+
try {
|
|
8069
|
+
const runtime = runtimeContext(context);
|
|
8070
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8071
|
+
const result = await genericKv(runtime, space).delete(input.key, {
|
|
8072
|
+
...input.etag === void 0 ? {} : { ifMatch: input.etag }
|
|
8073
|
+
});
|
|
8074
|
+
if (!result.ok) return kvFailure(result.error, "delete the KV value");
|
|
8075
|
+
return {
|
|
8076
|
+
status: "ok",
|
|
8077
|
+
output: {
|
|
8078
|
+
space,
|
|
8079
|
+
key: input.key,
|
|
8080
|
+
deleted: true,
|
|
8081
|
+
...result.data.headers.etag === void 0 ? {} : { etag: result.data.headers.etag }
|
|
8082
|
+
}
|
|
8083
|
+
};
|
|
8084
|
+
} catch (error) {
|
|
8085
|
+
return caughtKvFailure(error, "delete the KV value");
|
|
8086
|
+
}
|
|
8087
|
+
}
|
|
7909
8088
|
function runtimeContext(context) {
|
|
7910
8089
|
if (context.runtime === void 0) {
|
|
7911
8090
|
throw new TypeError("Authenticated operation runtime is unavailable.");
|
|
@@ -7915,15 +8094,19 @@ function runtimeContext(context) {
|
|
|
7915
8094
|
function runtimeNode(context) {
|
|
7916
8095
|
return runtimeContext(context).runtime.node;
|
|
7917
8096
|
}
|
|
8097
|
+
function genericKv(context, space) {
|
|
8098
|
+
return runtimeNode(context).kvForSpace(space);
|
|
8099
|
+
}
|
|
7918
8100
|
function resolveSpace(context, space) {
|
|
7919
8101
|
return operationSpaceResolver(context.runtime.node, context.summary.space)(space);
|
|
7920
8102
|
}
|
|
7921
|
-
function
|
|
8103
|
+
function resolveGenericKvSpace(context, space) {
|
|
7922
8104
|
const resolved = resolveSpace(context, space);
|
|
7923
|
-
|
|
8105
|
+
const protectedName = resolved.split(":").at(-1)?.toLowerCase();
|
|
8106
|
+
if (protectedName === "secrets" || protectedName === "account") {
|
|
7924
8107
|
throw new OperationInvocationError(operationError(
|
|
7925
8108
|
"INPUT_INVALID",
|
|
7926
|
-
"Generic KV operations cannot access
|
|
8109
|
+
"Generic KV operations cannot access TinyCloud account or secrets spaces."
|
|
7927
8110
|
));
|
|
7928
8111
|
}
|
|
7929
8112
|
return resolved;
|
|
@@ -7932,13 +8115,57 @@ async function readAccountRegistry(context, prefix) {
|
|
|
7932
8115
|
const runtime = runtimeContext(context);
|
|
7933
8116
|
const accountSpace = resolveSpace(runtime, "account");
|
|
7934
8117
|
const kv = runtimeNode(runtime).kvForSpace(accountSpace);
|
|
7935
|
-
const listed = await kv.list({ prefix });
|
|
7936
|
-
if (!listed.ok) return { ok: false };
|
|
8118
|
+
const listed = await kv.list({ prefix, limit: MAX_ACCOUNT_REGISTRY_RECORDS });
|
|
8119
|
+
if (!listed.ok) return { ok: false, outcome: nodeFailure("list the account registry") };
|
|
8120
|
+
if (listed.data.truncated === true) {
|
|
8121
|
+
return {
|
|
8122
|
+
ok: false,
|
|
8123
|
+
outcome: {
|
|
8124
|
+
status: "error",
|
|
8125
|
+
error: operationError(
|
|
8126
|
+
"OUTPUT_INVALID",
|
|
8127
|
+
`The TinyCloud account registry exceeds the ${MAX_ACCOUNT_REGISTRY_RECORDS}-record exploration limit.`
|
|
8128
|
+
)
|
|
8129
|
+
}
|
|
8130
|
+
};
|
|
8131
|
+
}
|
|
7937
8132
|
const records = [];
|
|
8133
|
+
let totalBytes = 0;
|
|
7938
8134
|
for (const key of listed.data.keys) {
|
|
7939
|
-
const loaded = await kv.get(key
|
|
7940
|
-
|
|
7941
|
-
|
|
8135
|
+
const loaded = await kv.get(key, {
|
|
8136
|
+
binary: true,
|
|
8137
|
+
maxResponseBytes: MAX_KV_VALUE_BYTES
|
|
8138
|
+
});
|
|
8139
|
+
if (!loaded.ok) {
|
|
8140
|
+
return { ok: false, outcome: kvFailure(loaded.error, "read the account registry") };
|
|
8141
|
+
}
|
|
8142
|
+
const bytes = loaded.data.data;
|
|
8143
|
+
totalBytes += bytes.byteLength;
|
|
8144
|
+
if (bytes.byteLength > MAX_KV_VALUE_BYTES || totalBytes > MAX_ACCOUNT_REGISTRY_BYTES) {
|
|
8145
|
+
return {
|
|
8146
|
+
ok: false,
|
|
8147
|
+
outcome: {
|
|
8148
|
+
status: "error",
|
|
8149
|
+
error: operationError(
|
|
8150
|
+
"KV_RESPONSE_TOO_LARGE",
|
|
8151
|
+
`The TinyCloud account registry exceeds the ${MAX_ACCOUNT_REGISTRY_BYTES}-byte exploration limit.`
|
|
8152
|
+
)
|
|
8153
|
+
}
|
|
8154
|
+
};
|
|
8155
|
+
}
|
|
8156
|
+
try {
|
|
8157
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
8158
|
+
if (!isRecord2(value)) throw new TypeError("Account registry values must be JSON objects.");
|
|
8159
|
+
records.push({ key, value });
|
|
8160
|
+
} catch {
|
|
8161
|
+
return {
|
|
8162
|
+
ok: false,
|
|
8163
|
+
outcome: {
|
|
8164
|
+
status: "error",
|
|
8165
|
+
error: operationError("OUTPUT_INVALID", "The TinyCloud account registry contains an invalid record.")
|
|
8166
|
+
}
|
|
8167
|
+
};
|
|
8168
|
+
}
|
|
7942
8169
|
}
|
|
7943
8170
|
return { ok: true, records };
|
|
7944
8171
|
}
|
|
@@ -7984,15 +8211,110 @@ function stringField2(record, ...keys) {
|
|
|
7984
8211
|
function isRecord2(value) {
|
|
7985
8212
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7986
8213
|
}
|
|
7987
|
-
function encodeKvValue(value) {
|
|
7988
|
-
if (
|
|
7989
|
-
return { value: Buffer.from(value).toString("base64"), encoding: "base64" };
|
|
8214
|
+
function encodeKvValue(value, representation) {
|
|
8215
|
+
if (representation === "base64") {
|
|
8216
|
+
return { ok: true, value: Buffer.from(value).toString("base64"), encoding: "base64" };
|
|
8217
|
+
}
|
|
8218
|
+
let text;
|
|
8219
|
+
try {
|
|
8220
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
8221
|
+
} catch {
|
|
8222
|
+
return {
|
|
8223
|
+
ok: false,
|
|
8224
|
+
outcome: { status: "error", error: operationError("OUTPUT_INVALID", "The KV value is not valid UTF-8.") }
|
|
8225
|
+
};
|
|
8226
|
+
}
|
|
8227
|
+
if (representation === "text") return { ok: true, value: text, encoding: "text" };
|
|
8228
|
+
try {
|
|
8229
|
+
const parsed = JsonValueSchema.safeParse(JSON.parse(text));
|
|
8230
|
+
if (!parsed.success) {
|
|
8231
|
+
return {
|
|
8232
|
+
ok: false,
|
|
8233
|
+
outcome: {
|
|
8234
|
+
status: "error",
|
|
8235
|
+
error: operationError(
|
|
8236
|
+
"OUTPUT_INVALID",
|
|
8237
|
+
"The KV JSON contains a number that cannot be represented safely."
|
|
8238
|
+
)
|
|
8239
|
+
}
|
|
8240
|
+
};
|
|
8241
|
+
}
|
|
8242
|
+
return { ok: true, value: parsed.data, encoding: "json" };
|
|
8243
|
+
} catch {
|
|
8244
|
+
return {
|
|
8245
|
+
ok: false,
|
|
8246
|
+
outcome: { status: "error", error: operationError("OUTPUT_INVALID", "The KV value is not valid JSON.") }
|
|
8247
|
+
};
|
|
8248
|
+
}
|
|
8249
|
+
}
|
|
8250
|
+
function decodeKvPutContent(content) {
|
|
8251
|
+
let bytes;
|
|
8252
|
+
let contentType;
|
|
8253
|
+
if (content.encoding === "utf8") {
|
|
8254
|
+
bytes = new TextEncoder().encode(content.value);
|
|
8255
|
+
contentType = "text/plain;charset=UTF-8";
|
|
8256
|
+
} else if (content.encoding === "json") {
|
|
8257
|
+
bytes = new TextEncoder().encode(JSON.stringify(content.value));
|
|
8258
|
+
contentType = "application/json";
|
|
8259
|
+
} else {
|
|
8260
|
+
if (!isCanonicalBase64(content.value)) return void 0;
|
|
8261
|
+
bytes = new Uint8Array(Buffer.from(content.value, "base64"));
|
|
8262
|
+
contentType = "application/octet-stream";
|
|
8263
|
+
}
|
|
8264
|
+
return { bytes, byteLength: bytes.byteLength, contentType };
|
|
8265
|
+
}
|
|
8266
|
+
function isCanonicalBase64(value) {
|
|
8267
|
+
if (value.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
8268
|
+
return false;
|
|
7990
8269
|
}
|
|
8270
|
+
return Buffer.from(value, "base64").toString("base64") === value;
|
|
8271
|
+
}
|
|
8272
|
+
function projectKvMetadata(headers) {
|
|
7991
8273
|
return {
|
|
7992
|
-
|
|
7993
|
-
|
|
8274
|
+
...headers.etag === void 0 ? {} : { etag: headers.etag },
|
|
8275
|
+
...headers.contentType === void 0 ? {} : { contentType: headers.contentType },
|
|
8276
|
+
...headers.lastModified === void 0 ? {} : { lastModified: headers.lastModified },
|
|
8277
|
+
...headers.contentLength === void 0 ? {} : { contentLength: headers.contentLength }
|
|
7994
8278
|
};
|
|
7995
8279
|
}
|
|
8280
|
+
function caughtKvFailure(error, action) {
|
|
8281
|
+
if (error instanceof OperationInvocationError) return { status: "error", error: error.operationError };
|
|
8282
|
+
return nodeFailure(action);
|
|
8283
|
+
}
|
|
8284
|
+
function accountRegistryOutput(output) {
|
|
8285
|
+
if (Buffer.byteLength(JSON.stringify(output), "utf8") > MAX_ACCOUNT_REGISTRY_BYTES) {
|
|
8286
|
+
return {
|
|
8287
|
+
status: "error",
|
|
8288
|
+
error: operationError(
|
|
8289
|
+
"KV_RESPONSE_TOO_LARGE",
|
|
8290
|
+
`The TinyCloud account registry exceeds the ${MAX_ACCOUNT_REGISTRY_BYTES}-byte exploration limit.`
|
|
8291
|
+
)
|
|
8292
|
+
};
|
|
8293
|
+
}
|
|
8294
|
+
return { status: "ok", output };
|
|
8295
|
+
}
|
|
8296
|
+
function kvFailure(error, action) {
|
|
8297
|
+
if (error.code === "KV_NOT_FOUND") {
|
|
8298
|
+
return { status: "error", error: operationError("KV_NOT_FOUND", "The TinyCloud KV key was not found.") };
|
|
8299
|
+
}
|
|
8300
|
+
if (error.code === "KV_PRECONDITION_FAILED") {
|
|
8301
|
+
return { status: "error", error: operationError("KV_PRECONDITION_FAILED", "The TinyCloud KV object changed or already exists.") };
|
|
8302
|
+
}
|
|
8303
|
+
if (error.code === "KV_CONFLICT") {
|
|
8304
|
+
return {
|
|
8305
|
+
status: "error",
|
|
8306
|
+
error: operationError(
|
|
8307
|
+
"KV_CONFLICT",
|
|
8308
|
+
"A database serialization conflict prevented the conditional KV mutation; re-read the key state, which may still be absent, before deciding whether to retry.",
|
|
8309
|
+
{ retryable: true }
|
|
8310
|
+
)
|
|
8311
|
+
};
|
|
8312
|
+
}
|
|
8313
|
+
if (error.code === "KV_RESPONSE_TOO_LARGE") {
|
|
8314
|
+
return { status: "error", error: operationError("KV_RESPONSE_TOO_LARGE", `The TinyCloud KV value exceeds ${MAX_KV_VALUE_BYTES} bytes.`) };
|
|
8315
|
+
}
|
|
8316
|
+
return nodeFailure(action);
|
|
8317
|
+
}
|
|
7996
8318
|
function nodeFailure(action) {
|
|
7997
8319
|
return {
|
|
7998
8320
|
status: "error",
|
|
@@ -8003,13 +8325,17 @@ function nodeFailure(action) {
|
|
|
8003
8325
|
)
|
|
8004
8326
|
};
|
|
8005
8327
|
}
|
|
8006
|
-
var import_zod4, EmptyInputSchema2, SpaceSchema, PrefixSchema, KeySchema, AccountSpaceSchema, AccountSpacesOutputSchema, AccountApplicationSchema, AccountApplicationsOutputSchema, KvListInputSchema, KvListOutputSchema, KvGetInputSchema, KvGetOutputSchema, AUTHENTICATED_POSTURES, EXPLORATION_EXPOSURE, ACCOUNT_SPACES_SENSITIVITY, ACCOUNT_APPLICATIONS_SENSITIVITY, KV_LIST_SENSITIVITY, KV_GET_SENSITIVITY, explorationOperationDefinitions;
|
|
8328
|
+
var import_zod4, MAX_KV_VALUE_BYTES, DEFAULT_KV_LIST_LIMIT, MAX_ACCOUNT_REGISTRY_RECORDS, MAX_ACCOUNT_REGISTRY_BYTES, EmptyInputSchema2, SpaceSchema, PrefixSchema, KeySchema, LimitSchema, StrongEtagSchema, ContentTypeSchema, JsonNumberSchema, JsonValueSchema, KvMetadataSchema, AccountSpaceSchema, AccountSpacesOutputSchema, AccountApplicationSchema, AccountApplicationsOutputSchema, KvListInputSchema, KvListOutputSchema, KvGetInputSchema, KvGetOutputSchema, KvPutContentSchema, KvPutCommonSchema, KvPutInputSchema, KvPutOutputSchema, KvHeadInputSchema, KvHeadOutputSchema, KvDeleteInputSchema, KvDeleteOutputSchema, AUTHENTICATED_POSTURES, EXPLORATION_EXPOSURE, ACCOUNT_SPACES_SENSITIVITY, ACCOUNT_APPLICATIONS_SENSITIVITY, KV_LIST_SENSITIVITY, KV_GET_SENSITIVITY, KV_PUT_SENSITIVITY, KV_KEY_SENSITIVITY, explorationOperationDefinitions;
|
|
8007
8329
|
var init_exploration = __esm({
|
|
8008
8330
|
"src/operations/exploration.ts"() {
|
|
8009
8331
|
"use strict";
|
|
8010
8332
|
import_zod4 = require("zod");
|
|
8011
8333
|
init_errors();
|
|
8012
8334
|
init_secrets();
|
|
8335
|
+
MAX_KV_VALUE_BYTES = 1024 * 1024;
|
|
8336
|
+
DEFAULT_KV_LIST_LIMIT = 100;
|
|
8337
|
+
MAX_ACCOUNT_REGISTRY_RECORDS = 1e3;
|
|
8338
|
+
MAX_ACCOUNT_REGISTRY_BYTES = 4 * 1024 * 1024;
|
|
8013
8339
|
EmptyInputSchema2 = import_zod4.z.object({}).strict();
|
|
8014
8340
|
SpaceSchema = import_zod4.z.string().min(1).refine(
|
|
8015
8341
|
(space) => (/^[A-Za-z0-9_-]+$/.test(space) || space.startsWith("tinycloud:")) && !space.includes("*"),
|
|
@@ -8023,6 +8349,33 @@ var init_exploration = __esm({
|
|
|
8023
8349
|
(key) => key !== "/" && !key.endsWith("/") && !key.includes("*"),
|
|
8024
8350
|
"Invalid KV key."
|
|
8025
8351
|
);
|
|
8352
|
+
LimitSchema = import_zod4.z.number().int().min(1).max(1e3);
|
|
8353
|
+
StrongEtagSchema = import_zod4.z.string().regex(
|
|
8354
|
+
/^"blake3-[0-9a-f]{64}"$/,
|
|
8355
|
+
"A strong TinyCloud BLAKE3 ETag is required."
|
|
8356
|
+
);
|
|
8357
|
+
ContentTypeSchema = import_zod4.z.string().min(1).max(128).refine(
|
|
8358
|
+
(value) => !/[\x00-\x1f\x7f]/.test(value),
|
|
8359
|
+
"Invalid content type."
|
|
8360
|
+
);
|
|
8361
|
+
JsonNumberSchema = import_zod4.z.number().finite().refine(
|
|
8362
|
+
(value) => !Number.isInteger(value) || Number.isSafeInteger(value),
|
|
8363
|
+
"JSON integer values must be JavaScript safe integers."
|
|
8364
|
+
);
|
|
8365
|
+
JsonValueSchema = import_zod4.z.lazy(() => import_zod4.z.union([
|
|
8366
|
+
import_zod4.z.null(),
|
|
8367
|
+
import_zod4.z.boolean(),
|
|
8368
|
+
JsonNumberSchema,
|
|
8369
|
+
import_zod4.z.string(),
|
|
8370
|
+
import_zod4.z.array(JsonValueSchema),
|
|
8371
|
+
import_zod4.z.record(JsonValueSchema)
|
|
8372
|
+
]));
|
|
8373
|
+
KvMetadataSchema = import_zod4.z.object({
|
|
8374
|
+
etag: import_zod4.z.string().optional(),
|
|
8375
|
+
contentType: import_zod4.z.string().optional(),
|
|
8376
|
+
lastModified: import_zod4.z.string().optional(),
|
|
8377
|
+
contentLength: import_zod4.z.number().int().nonnegative().optional()
|
|
8378
|
+
}).strict();
|
|
8026
8379
|
AccountSpaceSchema = import_zod4.z.object({
|
|
8027
8380
|
spaceId: import_zod4.z.string().min(1),
|
|
8028
8381
|
name: import_zod4.z.string().min(1),
|
|
@@ -8052,17 +8405,20 @@ var init_exploration = __esm({
|
|
|
8052
8405
|
}).strict();
|
|
8053
8406
|
KvListInputSchema = import_zod4.z.object({
|
|
8054
8407
|
space: SpaceSchema,
|
|
8055
|
-
prefix: PrefixSchema.optional()
|
|
8408
|
+
prefix: PrefixSchema.optional(),
|
|
8409
|
+
limit: LimitSchema.optional()
|
|
8056
8410
|
}).strict();
|
|
8057
8411
|
KvListOutputSchema = import_zod4.z.object({
|
|
8058
8412
|
space: import_zod4.z.string().min(1),
|
|
8059
8413
|
prefix: import_zod4.z.string(),
|
|
8060
8414
|
keys: import_zod4.z.array(import_zod4.z.string()),
|
|
8061
|
-
count: import_zod4.z.number().int().nonnegative()
|
|
8415
|
+
count: import_zod4.z.number().int().nonnegative(),
|
|
8416
|
+
truncated: import_zod4.z.boolean()
|
|
8062
8417
|
}).strict();
|
|
8063
8418
|
KvGetInputSchema = import_zod4.z.object({
|
|
8064
8419
|
space: SpaceSchema,
|
|
8065
|
-
key: KeySchema
|
|
8420
|
+
key: KeySchema,
|
|
8421
|
+
representation: import_zod4.z.enum(["base64", "text", "json"]).optional()
|
|
8066
8422
|
}).strict();
|
|
8067
8423
|
KvGetOutputSchema = import_zod4.z.object({
|
|
8068
8424
|
space: import_zod4.z.string().min(1),
|
|
@@ -8076,12 +8432,61 @@ var init_exploration = __esm({
|
|
|
8076
8432
|
import_zod4.z.record(import_zod4.z.unknown())
|
|
8077
8433
|
]),
|
|
8078
8434
|
encoding: import_zod4.z.enum(["json", "text", "base64"]),
|
|
8079
|
-
metadata:
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
}).strict()
|
|
8435
|
+
metadata: KvMetadataSchema,
|
|
8436
|
+
byteLength: import_zod4.z.number().int().nonnegative()
|
|
8437
|
+
}).strict();
|
|
8438
|
+
KvPutContentSchema = import_zod4.z.discriminatedUnion("encoding", [
|
|
8439
|
+
import_zod4.z.object({ encoding: import_zod4.z.literal("utf8"), value: import_zod4.z.string() }).strict(),
|
|
8440
|
+
import_zod4.z.object({ encoding: import_zod4.z.literal("json"), value: JsonValueSchema }).strict(),
|
|
8441
|
+
import_zod4.z.object({ encoding: import_zod4.z.literal("base64"), value: import_zod4.z.string() }).strict()
|
|
8442
|
+
]).superRefine((content, context) => {
|
|
8443
|
+
const decoded = decodeKvPutContent(content);
|
|
8444
|
+
if (decoded === void 0) {
|
|
8445
|
+
context.addIssue({ code: import_zod4.z.ZodIssueCode.custom, message: "Invalid canonical base64 content." });
|
|
8446
|
+
} else if (decoded.byteLength > MAX_KV_VALUE_BYTES) {
|
|
8447
|
+
context.addIssue({
|
|
8448
|
+
code: import_zod4.z.ZodIssueCode.too_big,
|
|
8449
|
+
type: "array",
|
|
8450
|
+
maximum: MAX_KV_VALUE_BYTES,
|
|
8451
|
+
inclusive: true,
|
|
8452
|
+
message: `KV content must not exceed ${MAX_KV_VALUE_BYTES} bytes.`
|
|
8453
|
+
});
|
|
8454
|
+
}
|
|
8455
|
+
});
|
|
8456
|
+
KvPutCommonSchema = {
|
|
8457
|
+
space: SpaceSchema,
|
|
8458
|
+
key: KeySchema,
|
|
8459
|
+
content: KvPutContentSchema,
|
|
8460
|
+
contentType: ContentTypeSchema.optional()
|
|
8461
|
+
};
|
|
8462
|
+
KvPutInputSchema = import_zod4.z.discriminatedUnion("mode", [
|
|
8463
|
+
import_zod4.z.object({ ...KvPutCommonSchema, mode: import_zod4.z.literal("create") }).strict(),
|
|
8464
|
+
import_zod4.z.object({ ...KvPutCommonSchema, mode: import_zod4.z.literal("upsert") }).strict(),
|
|
8465
|
+
import_zod4.z.object({ ...KvPutCommonSchema, mode: import_zod4.z.literal("replace"), etag: StrongEtagSchema }).strict()
|
|
8466
|
+
]);
|
|
8467
|
+
KvPutOutputSchema = import_zod4.z.object({
|
|
8468
|
+
space: import_zod4.z.string().min(1),
|
|
8469
|
+
key: import_zod4.z.string().min(1),
|
|
8470
|
+
mode: import_zod4.z.enum(["create", "replace", "upsert"]),
|
|
8471
|
+
byteLength: import_zod4.z.number().int().nonnegative(),
|
|
8472
|
+
metadata: KvMetadataSchema
|
|
8473
|
+
}).strict();
|
|
8474
|
+
KvHeadInputSchema = import_zod4.z.object({ space: SpaceSchema, key: KeySchema }).strict();
|
|
8475
|
+
KvHeadOutputSchema = import_zod4.z.object({
|
|
8476
|
+
space: import_zod4.z.string().min(1),
|
|
8477
|
+
key: import_zod4.z.string().min(1),
|
|
8478
|
+
metadata: KvMetadataSchema
|
|
8479
|
+
}).strict();
|
|
8480
|
+
KvDeleteInputSchema = import_zod4.z.object({
|
|
8481
|
+
space: SpaceSchema,
|
|
8482
|
+
key: KeySchema,
|
|
8483
|
+
etag: StrongEtagSchema.optional()
|
|
8484
|
+
}).strict();
|
|
8485
|
+
KvDeleteOutputSchema = import_zod4.z.object({
|
|
8486
|
+
space: import_zod4.z.string().min(1),
|
|
8487
|
+
key: import_zod4.z.string().min(1),
|
|
8488
|
+
deleted: import_zod4.z.literal(true),
|
|
8489
|
+
etag: import_zod4.z.string().optional()
|
|
8085
8490
|
}).strict();
|
|
8086
8491
|
AUTHENTICATED_POSTURES = [
|
|
8087
8492
|
"owner-openkey",
|
|
@@ -8113,6 +8518,8 @@ var init_exploration = __esm({
|
|
|
8113
8518
|
input: ["/key"],
|
|
8114
8519
|
output: ["/value"]
|
|
8115
8520
|
};
|
|
8521
|
+
KV_PUT_SENSITIVITY = { input: ["/key", "/content"], output: [] };
|
|
8522
|
+
KV_KEY_SENSITIVITY = { input: ["/key"], output: [] };
|
|
8116
8523
|
explorationOperationDefinitions = [
|
|
8117
8524
|
{
|
|
8118
8525
|
id: "tinycloud.account.spaces.list",
|
|
@@ -8163,7 +8570,7 @@ var init_exploration = __esm({
|
|
|
8163
8570
|
id: "tinycloud.kv.get",
|
|
8164
8571
|
version: 1,
|
|
8165
8572
|
title: "Get a TinyCloud KV value",
|
|
8166
|
-
description: "Read one exact key
|
|
8573
|
+
description: "Read one exact key with a node-enforced one MiB response limit.",
|
|
8167
8574
|
input: KvGetInputSchema,
|
|
8168
8575
|
output: KvGetOutputSchema,
|
|
8169
8576
|
effects: ["read"],
|
|
@@ -8173,6 +8580,51 @@ var init_exploration = __esm({
|
|
|
8173
8580
|
sensitivity: KV_GET_SENSITIVITY,
|
|
8174
8581
|
authority: planKvGet,
|
|
8175
8582
|
execute: executeKvGet
|
|
8583
|
+
},
|
|
8584
|
+
{
|
|
8585
|
+
id: "tinycloud.kv.head",
|
|
8586
|
+
version: 1,
|
|
8587
|
+
title: "Inspect TinyCloud KV metadata",
|
|
8588
|
+
description: "Read metadata for one exact key without downloading its value.",
|
|
8589
|
+
input: KvHeadInputSchema,
|
|
8590
|
+
output: KvHeadOutputSchema,
|
|
8591
|
+
effects: ["read"],
|
|
8592
|
+
runtime: "authenticated",
|
|
8593
|
+
postures: AUTHENTICATED_POSTURES,
|
|
8594
|
+
exposure: EXPLORATION_EXPOSURE,
|
|
8595
|
+
sensitivity: KV_KEY_SENSITIVITY,
|
|
8596
|
+
authority: (context, input) => planExactKv(context, input.space, input.key, "tinycloud.kv/metadata"),
|
|
8597
|
+
execute: executeKvHead
|
|
8598
|
+
},
|
|
8599
|
+
{
|
|
8600
|
+
id: "tinycloud.kv.put",
|
|
8601
|
+
version: 1,
|
|
8602
|
+
title: "Write a TinyCloud KV value",
|
|
8603
|
+
description: "Create, conditionally replace, or explicitly upsert one exact KV key.",
|
|
8604
|
+
input: KvPutInputSchema,
|
|
8605
|
+
output: KvPutOutputSchema,
|
|
8606
|
+
effects: ["write"],
|
|
8607
|
+
runtime: "authenticated",
|
|
8608
|
+
postures: AUTHENTICATED_POSTURES,
|
|
8609
|
+
exposure: EXPLORATION_EXPOSURE,
|
|
8610
|
+
sensitivity: KV_PUT_SENSITIVITY,
|
|
8611
|
+
authority: (context, input) => planExactKv(context, input.space, input.key, "tinycloud.kv/put"),
|
|
8612
|
+
execute: executeKvPut
|
|
8613
|
+
},
|
|
8614
|
+
{
|
|
8615
|
+
id: "tinycloud.kv.delete",
|
|
8616
|
+
version: 1,
|
|
8617
|
+
title: "Delete a TinyCloud KV value",
|
|
8618
|
+
description: "Delete one exact KV key, optionally only when its ETag still matches.",
|
|
8619
|
+
input: KvDeleteInputSchema,
|
|
8620
|
+
output: KvDeleteOutputSchema,
|
|
8621
|
+
effects: ["destructive"],
|
|
8622
|
+
runtime: "authenticated",
|
|
8623
|
+
postures: AUTHENTICATED_POSTURES,
|
|
8624
|
+
exposure: EXPLORATION_EXPOSURE,
|
|
8625
|
+
sensitivity: KV_KEY_SENSITIVITY,
|
|
8626
|
+
authority: (context, input) => planExactKv(context, input.space, input.key, "tinycloud.kv/del"),
|
|
8627
|
+
execute: executeKvDelete
|
|
8176
8628
|
}
|
|
8177
8629
|
];
|
|
8178
8630
|
}
|
|
@@ -8387,6 +8839,541 @@ var init_secrets_get = __esm({
|
|
|
8387
8839
|
}
|
|
8388
8840
|
});
|
|
8389
8841
|
|
|
8842
|
+
// src/operations/sql.ts
|
|
8843
|
+
async function planSqlRead(context, input) {
|
|
8844
|
+
const space = resolveSqlSpace(context, input.space);
|
|
8845
|
+
return [{
|
|
8846
|
+
service: "tinycloud.sql",
|
|
8847
|
+
space,
|
|
8848
|
+
path: input.database,
|
|
8849
|
+
actions: ["tinycloud.sql/read"]
|
|
8850
|
+
}];
|
|
8851
|
+
}
|
|
8852
|
+
async function planSqlWrite(context, input) {
|
|
8853
|
+
const space = resolveSqlSpace(context, input.space);
|
|
8854
|
+
return [{
|
|
8855
|
+
service: "tinycloud.sql",
|
|
8856
|
+
space,
|
|
8857
|
+
path: input.database,
|
|
8858
|
+
actions: ["tinycloud.sql/write"],
|
|
8859
|
+
description: SQL_WRITE_AUTHORITY_NOTICE
|
|
8860
|
+
}];
|
|
8861
|
+
}
|
|
8862
|
+
async function executeSqlSchemaInspect(context, input) {
|
|
8863
|
+
try {
|
|
8864
|
+
const runtime = runtimeContext2(context);
|
|
8865
|
+
const space = resolveSqlSpace(runtime, input.space);
|
|
8866
|
+
const result = await runtimeNode2(runtime).sqlForSpace(space).db(input.database).query(SCHEMA_QUERY, [], { maxRows: SCHEMA_MAX_ROWS, maxBytes: SCHEMA_MAX_BYTES });
|
|
8867
|
+
if (!result.ok) return sqlServiceFailure(result.error, "inspect the SQLite schema");
|
|
8868
|
+
const normalized = normalizeQueryResult(result.data, SCHEMA_MAX_ROWS, SCHEMA_MAX_BYTES);
|
|
8869
|
+
const objects = normalized.rows.map((row) => schemaObject(row));
|
|
8870
|
+
return {
|
|
8871
|
+
status: "ok",
|
|
8872
|
+
output: {
|
|
8873
|
+
space,
|
|
8874
|
+
database: input.database,
|
|
8875
|
+
objects,
|
|
8876
|
+
count: objects.length,
|
|
8877
|
+
limits: limitsOutput(SCHEMA_MAX_ROWS, SCHEMA_MAX_BYTES)
|
|
8878
|
+
}
|
|
8879
|
+
};
|
|
8880
|
+
} catch (error) {
|
|
8881
|
+
return sqlFailure(error, "inspect the SQLite schema");
|
|
8882
|
+
}
|
|
8883
|
+
}
|
|
8884
|
+
async function executeSqlQuery(context, input) {
|
|
8885
|
+
try {
|
|
8886
|
+
if (!isSingleReadQuery(input.sql)) {
|
|
8887
|
+
return {
|
|
8888
|
+
status: "error",
|
|
8889
|
+
error: operationError(
|
|
8890
|
+
"SQL_QUERY_INVALID",
|
|
8891
|
+
"SQL must parse as exactly one SQLite SELECT statement."
|
|
8892
|
+
)
|
|
8893
|
+
};
|
|
8894
|
+
}
|
|
8895
|
+
const runtime = runtimeContext2(context);
|
|
8896
|
+
const space = resolveSqlSpace(runtime, input.space);
|
|
8897
|
+
const maxRows = input.maxRows ?? DEFAULT_MAX_ROWS;
|
|
8898
|
+
const maxBytes = input.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
8899
|
+
const params = (input.params ?? []).map(decodeSqlInputValue);
|
|
8900
|
+
const result = await runtimeNode2(runtime).sqlForSpace(space).db(input.database).query(input.sql, params, { maxRows, maxBytes });
|
|
8901
|
+
if (!result.ok) return sqlServiceFailure(result.error, "run the SQLite query");
|
|
8902
|
+
const normalized = normalizeQueryResult(result.data, maxRows, maxBytes);
|
|
8903
|
+
return {
|
|
8904
|
+
status: "ok",
|
|
8905
|
+
output: {
|
|
8906
|
+
space,
|
|
8907
|
+
database: input.database,
|
|
8908
|
+
columns: normalized.columns,
|
|
8909
|
+
rows: normalized.rows,
|
|
8910
|
+
rowCount: normalized.rows.length,
|
|
8911
|
+
limits: limitsOutput(maxRows, maxBytes)
|
|
8912
|
+
}
|
|
8913
|
+
};
|
|
8914
|
+
} catch (error) {
|
|
8915
|
+
return sqlFailure(error, "run the SQLite query");
|
|
8916
|
+
}
|
|
8917
|
+
}
|
|
8918
|
+
async function executeSqlDml(context, input) {
|
|
8919
|
+
try {
|
|
8920
|
+
const statementType = parseSingleDmlStatement(input.sql, input.params.length);
|
|
8921
|
+
if (statementType === void 0) {
|
|
8922
|
+
return {
|
|
8923
|
+
status: "error",
|
|
8924
|
+
error: operationError(
|
|
8925
|
+
"SQL_QUERY_INVALID",
|
|
8926
|
+
"SQL must parse as exactly one parameterized INSERT, UPDATE, or DELETE with one value per positional placeholder."
|
|
8927
|
+
)
|
|
8928
|
+
};
|
|
8929
|
+
}
|
|
8930
|
+
const runtime = runtimeContext2(context);
|
|
8931
|
+
const space = resolveSqlSpace(runtime, input.space);
|
|
8932
|
+
const result = await runtimeNode2(runtime).sqlForSpace(space).db(input.database).execute(input.sql, input.params.map(decodeSqlInputValue));
|
|
8933
|
+
if (!result.ok) return sqlMutationFailure();
|
|
8934
|
+
const normalized = normalizeExecuteResult(result.data);
|
|
8935
|
+
return {
|
|
8936
|
+
status: "ok",
|
|
8937
|
+
output: {
|
|
8938
|
+
space,
|
|
8939
|
+
database: input.database,
|
|
8940
|
+
statementType,
|
|
8941
|
+
...normalized,
|
|
8942
|
+
authorityNotice: SQL_WRITE_AUTHORITY_NOTICE
|
|
8943
|
+
}
|
|
8944
|
+
};
|
|
8945
|
+
} catch (error) {
|
|
8946
|
+
return sqlFailure(error, "execute the SQLite statement");
|
|
8947
|
+
}
|
|
8948
|
+
}
|
|
8949
|
+
function isSingleReadQuery(sql) {
|
|
8950
|
+
const ast = parseSingleStatement(sql);
|
|
8951
|
+
return ast !== void 0 && ast.type === "select";
|
|
8952
|
+
}
|
|
8953
|
+
function parseSingleDmlStatement(sql, parameterCount) {
|
|
8954
|
+
const ast = parseSingleStatement(sql);
|
|
8955
|
+
if (ast === void 0 || ast.type !== "insert" && ast.type !== "update" && ast.type !== "delete" || ast.with !== void 0 && ast.with !== null) {
|
|
8956
|
+
return void 0;
|
|
8957
|
+
}
|
|
8958
|
+
const placeholders = countPositionalParameters(ast);
|
|
8959
|
+
return placeholders > 0 && placeholders === parameterCount ? ast.type : void 0;
|
|
8960
|
+
}
|
|
8961
|
+
function parseSingleStatement(sql) {
|
|
8962
|
+
try {
|
|
8963
|
+
const ast = sqlParser.astify(sql, { database: "sqlite" });
|
|
8964
|
+
return !Array.isArray(ast) && isRecord3(ast) ? ast : void 0;
|
|
8965
|
+
} catch {
|
|
8966
|
+
return void 0;
|
|
8967
|
+
}
|
|
8968
|
+
}
|
|
8969
|
+
function countPositionalParameters(value) {
|
|
8970
|
+
if (Array.isArray(value)) {
|
|
8971
|
+
return value.reduce((count, entry) => count + countPositionalParameters(entry), 0);
|
|
8972
|
+
}
|
|
8973
|
+
if (!isRecord3(value)) return 0;
|
|
8974
|
+
const current = value.type === "origin" && value.value === "?" ? 1 : 0;
|
|
8975
|
+
return Object.values(value).reduce(
|
|
8976
|
+
(count, entry) => count + countPositionalParameters(entry),
|
|
8977
|
+
current
|
|
8978
|
+
);
|
|
8979
|
+
}
|
|
8980
|
+
function decodeSqlInputValue(value) {
|
|
8981
|
+
if (isRecord3(value) && value.type === "blob") {
|
|
8982
|
+
return new Uint8Array(Buffer.from(value.base64, "base64"));
|
|
8983
|
+
}
|
|
8984
|
+
return value;
|
|
8985
|
+
}
|
|
8986
|
+
function normalizeQueryResult(value, maxRows, maxBytes) {
|
|
8987
|
+
if (!isRecord3(value) || !Array.isArray(value.columns) || !Array.isArray(value.rows)) {
|
|
8988
|
+
throw unsafeSqlValue("The node returned an invalid SQLite query result.");
|
|
8989
|
+
}
|
|
8990
|
+
const columns = value.columns.map((column) => {
|
|
8991
|
+
if (typeof column !== "string") {
|
|
8992
|
+
throw unsafeSqlValue("The node returned an invalid SQLite column name.");
|
|
8993
|
+
}
|
|
8994
|
+
return column;
|
|
8995
|
+
});
|
|
8996
|
+
const rows = value.rows.map((row) => {
|
|
8997
|
+
if (!Array.isArray(row) || row.length !== columns.length) {
|
|
8998
|
+
throw unsafeSqlValue("The node returned an invalid SQLite row.");
|
|
8999
|
+
}
|
|
9000
|
+
return row.map(normalizeSqlOutputValue);
|
|
9001
|
+
});
|
|
9002
|
+
const serializedBytes = Buffer.byteLength(JSON.stringify({ columns, rows }), "utf8");
|
|
9003
|
+
if (rows.length > maxRows || serializedBytes > maxBytes) {
|
|
9004
|
+
throw new OperationInvocationError(operationError(
|
|
9005
|
+
"SQL_RESULT_LIMIT_EXCEEDED",
|
|
9006
|
+
"The SQLite query result exceeded the requested result limits.",
|
|
9007
|
+
{
|
|
9008
|
+
details: {
|
|
9009
|
+
maxRows,
|
|
9010
|
+
maxBytes,
|
|
9011
|
+
returnedRows: rows.length,
|
|
9012
|
+
returnedBytes: serializedBytes
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
9015
|
+
));
|
|
9016
|
+
}
|
|
9017
|
+
return { columns, rows };
|
|
9018
|
+
}
|
|
9019
|
+
function normalizeSqlOutputValue(value) {
|
|
9020
|
+
if (value === null || typeof value === "string") return value;
|
|
9021
|
+
if (typeof value === "number") {
|
|
9022
|
+
if (!Number.isFinite(value) || Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
9023
|
+
throw unsafeSqlValue("The node returned an integer that cannot be represented safely in JavaScript.");
|
|
9024
|
+
}
|
|
9025
|
+
return value;
|
|
9026
|
+
}
|
|
9027
|
+
if (value instanceof Uint8Array) return encodeBlob(value);
|
|
9028
|
+
if (Array.isArray(value) && value.every(isByte)) {
|
|
9029
|
+
return encodeBlob(Uint8Array.from(value));
|
|
9030
|
+
}
|
|
9031
|
+
if (isRecord3(value) && value.type === "Buffer" && Array.isArray(value.data) && value.data.every(isByte)) {
|
|
9032
|
+
return encodeBlob(Uint8Array.from(value.data));
|
|
9033
|
+
}
|
|
9034
|
+
throw unsafeSqlValue("The node returned an unsupported SQLite value.");
|
|
9035
|
+
}
|
|
9036
|
+
function normalizeExecuteResult(value) {
|
|
9037
|
+
if (!isRecord3(value) || !Number.isSafeInteger(value.changes) || value.changes < 0 || value.lastInsertRowId !== null && !Number.isSafeInteger(value.lastInsertRowId)) {
|
|
9038
|
+
throw unsafeSqlValue("The node returned SQLite mutation metadata that cannot be represented safely in JavaScript.");
|
|
9039
|
+
}
|
|
9040
|
+
return {
|
|
9041
|
+
changes: value.changes,
|
|
9042
|
+
lastInsertRowId: value.lastInsertRowId
|
|
9043
|
+
};
|
|
9044
|
+
}
|
|
9045
|
+
function schemaObject(row) {
|
|
9046
|
+
const [type, name, tableName, sql] = row;
|
|
9047
|
+
if (type !== "table" && type !== "view" && type !== "index" && type !== "trigger" || typeof name !== "string" || typeof tableName !== "string" || sql !== null && typeof sql !== "string") {
|
|
9048
|
+
throw unsafeSqlValue("The node returned an invalid SQLite schema record.");
|
|
9049
|
+
}
|
|
9050
|
+
return {
|
|
9051
|
+
type,
|
|
9052
|
+
name,
|
|
9053
|
+
tableName,
|
|
9054
|
+
...sql === null ? {} : { sql }
|
|
9055
|
+
};
|
|
9056
|
+
}
|
|
9057
|
+
function limitsOutput(maxRows, maxBytes) {
|
|
9058
|
+
return { maxRows, maxBytes, enforcement: "node-requested-client-verified" };
|
|
9059
|
+
}
|
|
9060
|
+
function runtimeContext2(context) {
|
|
9061
|
+
if (context.runtime === void 0) {
|
|
9062
|
+
throw new TypeError("Authenticated operation runtime is unavailable.");
|
|
9063
|
+
}
|
|
9064
|
+
return context;
|
|
9065
|
+
}
|
|
9066
|
+
function runtimeNode2(context) {
|
|
9067
|
+
return context.runtime.node;
|
|
9068
|
+
}
|
|
9069
|
+
function resolveSqlSpace(context, space) {
|
|
9070
|
+
const resolved = operationSpaceResolver(
|
|
9071
|
+
context.runtime.node,
|
|
9072
|
+
context.summary.space
|
|
9073
|
+
)(space);
|
|
9074
|
+
const name = resolved.split(":").at(-1)?.toLowerCase();
|
|
9075
|
+
if (name === "secrets" || name === "account") {
|
|
9076
|
+
throw new OperationInvocationError(operationError(
|
|
9077
|
+
"INPUT_INVALID",
|
|
9078
|
+
"Generic SQL operations cannot access protected TinyCloud account or secrets spaces."
|
|
9079
|
+
));
|
|
9080
|
+
}
|
|
9081
|
+
return resolved;
|
|
9082
|
+
}
|
|
9083
|
+
function encodeBlob(value) {
|
|
9084
|
+
return {
|
|
9085
|
+
type: "blob",
|
|
9086
|
+
base64: Buffer.from(value).toString("base64"),
|
|
9087
|
+
byteLength: value.byteLength
|
|
9088
|
+
};
|
|
9089
|
+
}
|
|
9090
|
+
function unsafeSqlValue(message) {
|
|
9091
|
+
return new OperationInvocationError(operationError("SQL_VALUE_UNSAFE", message));
|
|
9092
|
+
}
|
|
9093
|
+
function sqlFailure(error, action) {
|
|
9094
|
+
if (error instanceof OperationInvocationError) {
|
|
9095
|
+
return { status: "error", error: error.operationError };
|
|
9096
|
+
}
|
|
9097
|
+
return nodeFailure2(action);
|
|
9098
|
+
}
|
|
9099
|
+
function nodeFailure2(action) {
|
|
9100
|
+
return {
|
|
9101
|
+
status: "error",
|
|
9102
|
+
error: operationError(
|
|
9103
|
+
"NODE_ERROR",
|
|
9104
|
+
`The TinyCloud node could not ${action}.`,
|
|
9105
|
+
{ retryable: true }
|
|
9106
|
+
)
|
|
9107
|
+
};
|
|
9108
|
+
}
|
|
9109
|
+
function sqlServiceFailure(error, action) {
|
|
9110
|
+
if (isRecord3(error) && error.code === "SQL_RESPONSE_TOO_LARGE") {
|
|
9111
|
+
return {
|
|
9112
|
+
status: "error",
|
|
9113
|
+
error: operationError(
|
|
9114
|
+
"SQL_RESULT_LIMIT_EXCEEDED",
|
|
9115
|
+
"The SQLite query result exceeded the requested result limits."
|
|
9116
|
+
)
|
|
9117
|
+
};
|
|
9118
|
+
}
|
|
9119
|
+
return nodeFailure2(action);
|
|
9120
|
+
}
|
|
9121
|
+
function sqlMutationFailure() {
|
|
9122
|
+
return {
|
|
9123
|
+
status: "error",
|
|
9124
|
+
error: operationError(
|
|
9125
|
+
"SQL_EXECUTION_FAILED",
|
|
9126
|
+
"The SQLite statement outcome is unknown; inspect database state before considering another write.",
|
|
9127
|
+
{ retryable: false }
|
|
9128
|
+
)
|
|
9129
|
+
};
|
|
9130
|
+
}
|
|
9131
|
+
function isCanonicalBase642(value) {
|
|
9132
|
+
if (value === "") return true;
|
|
9133
|
+
if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) return false;
|
|
9134
|
+
return Buffer.from(value, "base64").toString("base64") === value;
|
|
9135
|
+
}
|
|
9136
|
+
function sqlInputValueBytes(value) {
|
|
9137
|
+
if (typeof value === "string") return Buffer.byteLength(value, "utf8");
|
|
9138
|
+
if (isRecord3(value) && value.type === "blob") {
|
|
9139
|
+
return Buffer.from(value.base64, "base64").byteLength;
|
|
9140
|
+
}
|
|
9141
|
+
return 8;
|
|
9142
|
+
}
|
|
9143
|
+
function isByte(value) {
|
|
9144
|
+
return Number.isInteger(value) && value >= 0 && value <= 255;
|
|
9145
|
+
}
|
|
9146
|
+
function isRecord3(value) {
|
|
9147
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9148
|
+
}
|
|
9149
|
+
var import_node_sql_parser, import_zod6, DEFAULT_MAX_ROWS, MAX_MAX_ROWS, DEFAULT_MAX_BYTES, MAX_MAX_BYTES, SCHEMA_MAX_ROWS, SCHEMA_MAX_BYTES, MAX_PARAMETERS, MAX_SQL_LENGTH, SQL_WRITE_AUTHORITY_NOTICE, SCHEMA_QUERY, sqlParser, SpaceSchema2, DatabaseSchema, SafeNumberSchema, Base64Schema, SqlInputValueSchema, SqlParamsSchema, RequiredSqlParamsSchema, SqlOutputValueSchema, SqlTargetInputSchema, SqlQueryInputSchema, SqlExecuteInputSchema, SqlLimitsOutputSchema, SqlSchemaInspectOutputSchema, SqlQueryOutputSchema, SqlExecuteOutputSchema, AUTHENTICATED_POSTURES2, SQL_EXPOSURE, SQL_SCHEMA_SENSITIVITY, SQL_QUERY_SENSITIVITY, SQL_EXECUTE_SENSITIVITY, sqlOperationDefinitions;
|
|
9150
|
+
var init_sql = __esm({
|
|
9151
|
+
"src/operations/sql.ts"() {
|
|
9152
|
+
"use strict";
|
|
9153
|
+
import_node_sql_parser = __toESM(require("node-sql-parser"), 1);
|
|
9154
|
+
import_zod6 = require("zod");
|
|
9155
|
+
init_errors();
|
|
9156
|
+
init_secrets();
|
|
9157
|
+
DEFAULT_MAX_ROWS = 100;
|
|
9158
|
+
MAX_MAX_ROWS = 1e3;
|
|
9159
|
+
DEFAULT_MAX_BYTES = 1024 * 1024;
|
|
9160
|
+
MAX_MAX_BYTES = 4 * 1024 * 1024;
|
|
9161
|
+
SCHEMA_MAX_ROWS = 500;
|
|
9162
|
+
SCHEMA_MAX_BYTES = 1024 * 1024;
|
|
9163
|
+
MAX_PARAMETERS = 100;
|
|
9164
|
+
MAX_SQL_LENGTH = 64 * 1024;
|
|
9165
|
+
SQL_WRITE_AUTHORITY_NOTICE = "Approving tinycloud.sql/write grants full read/write/schema mutation authority over this exact database; the MCP tool itself accepts only one parameterized INSERT, UPDATE, or DELETE.";
|
|
9166
|
+
SCHEMA_QUERY = `SELECT type, name, tbl_name, sql
|
|
9167
|
+
FROM sqlite_schema
|
|
9168
|
+
WHERE type IN ('table', 'view', 'index', 'trigger')
|
|
9169
|
+
AND name NOT LIKE 'sqlite_%'
|
|
9170
|
+
ORDER BY type, name`;
|
|
9171
|
+
sqlParser = new import_node_sql_parser.default.Parser();
|
|
9172
|
+
SpaceSchema2 = import_zod6.z.string().min(1).refine(
|
|
9173
|
+
(space) => (/^[A-Za-z0-9_-]+$/.test(space) || space.startsWith("tinycloud:")) && !space.includes("*"),
|
|
9174
|
+
"Invalid TinyCloud space."
|
|
9175
|
+
);
|
|
9176
|
+
DatabaseSchema = import_zod6.z.string().min(1).max(256).refine(
|
|
9177
|
+
(database) => database !== "/" && !database.endsWith("/") && !database.includes("*") && !/[\u0000-\u001f\u007f]/.test(database),
|
|
9178
|
+
"Invalid SQLite database name."
|
|
9179
|
+
);
|
|
9180
|
+
SafeNumberSchema = import_zod6.z.number().finite().refine(
|
|
9181
|
+
(value) => !Number.isInteger(value) || Number.isSafeInteger(value),
|
|
9182
|
+
"SQLite integer parameters must be JavaScript safe integers."
|
|
9183
|
+
);
|
|
9184
|
+
Base64Schema = import_zod6.z.string().max(Math.ceil(MAX_MAX_BYTES / 3) * 4).refine(
|
|
9185
|
+
isCanonicalBase642,
|
|
9186
|
+
"Invalid base64 BLOB value."
|
|
9187
|
+
);
|
|
9188
|
+
SqlInputValueSchema = import_zod6.z.union([
|
|
9189
|
+
import_zod6.z.null(),
|
|
9190
|
+
SafeNumberSchema,
|
|
9191
|
+
import_zod6.z.string().max(MAX_MAX_BYTES),
|
|
9192
|
+
import_zod6.z.object({ type: import_zod6.z.literal("blob"), base64: Base64Schema }).strict()
|
|
9193
|
+
]);
|
|
9194
|
+
SqlParamsSchema = import_zod6.z.array(SqlInputValueSchema).max(MAX_PARAMETERS).superRefine(
|
|
9195
|
+
(params, context) => {
|
|
9196
|
+
const totalBytes = params.reduce(
|
|
9197
|
+
(total, value) => total + sqlInputValueBytes(value),
|
|
9198
|
+
0
|
|
9199
|
+
);
|
|
9200
|
+
if (totalBytes > MAX_MAX_BYTES) {
|
|
9201
|
+
context.addIssue({
|
|
9202
|
+
code: import_zod6.z.ZodIssueCode.custom,
|
|
9203
|
+
message: "SQLite query parameters exceed the 4 MiB input limit."
|
|
9204
|
+
});
|
|
9205
|
+
}
|
|
9206
|
+
}
|
|
9207
|
+
);
|
|
9208
|
+
RequiredSqlParamsSchema = import_zod6.z.array(SqlInputValueSchema).min(1).max(MAX_PARAMETERS).superRefine(
|
|
9209
|
+
(params, context) => {
|
|
9210
|
+
const totalBytes = params.reduce(
|
|
9211
|
+
(total, value) => total + sqlInputValueBytes(value),
|
|
9212
|
+
0
|
|
9213
|
+
);
|
|
9214
|
+
if (totalBytes > MAX_MAX_BYTES) {
|
|
9215
|
+
context.addIssue({
|
|
9216
|
+
code: import_zod6.z.ZodIssueCode.custom,
|
|
9217
|
+
message: "SQLite query parameters exceed the 4 MiB input limit."
|
|
9218
|
+
});
|
|
9219
|
+
}
|
|
9220
|
+
}
|
|
9221
|
+
);
|
|
9222
|
+
SqlOutputValueSchema = import_zod6.z.union([
|
|
9223
|
+
import_zod6.z.null(),
|
|
9224
|
+
SafeNumberSchema,
|
|
9225
|
+
import_zod6.z.string(),
|
|
9226
|
+
import_zod6.z.object({
|
|
9227
|
+
type: import_zod6.z.literal("blob"),
|
|
9228
|
+
base64: import_zod6.z.string(),
|
|
9229
|
+
byteLength: import_zod6.z.number().int().nonnegative()
|
|
9230
|
+
}).strict()
|
|
9231
|
+
]);
|
|
9232
|
+
SqlTargetInputSchema = import_zod6.z.object({
|
|
9233
|
+
space: SpaceSchema2,
|
|
9234
|
+
database: DatabaseSchema
|
|
9235
|
+
}).strict();
|
|
9236
|
+
SqlQueryInputSchema = import_zod6.z.object({
|
|
9237
|
+
space: SpaceSchema2,
|
|
9238
|
+
database: DatabaseSchema,
|
|
9239
|
+
sql: import_zod6.z.string().min(1).max(MAX_SQL_LENGTH).superRefine((sql, context) => {
|
|
9240
|
+
if (!isSingleReadQuery(sql)) {
|
|
9241
|
+
context.addIssue({
|
|
9242
|
+
code: import_zod6.z.ZodIssueCode.custom,
|
|
9243
|
+
message: "SQL must parse as exactly one SQLite SELECT statement."
|
|
9244
|
+
});
|
|
9245
|
+
}
|
|
9246
|
+
}),
|
|
9247
|
+
params: SqlParamsSchema.optional(),
|
|
9248
|
+
maxRows: import_zod6.z.number().int().positive().max(MAX_MAX_ROWS).optional(),
|
|
9249
|
+
maxBytes: import_zod6.z.number().int().positive().max(MAX_MAX_BYTES).optional()
|
|
9250
|
+
}).strict();
|
|
9251
|
+
SqlExecuteInputSchema = import_zod6.z.object({
|
|
9252
|
+
space: SpaceSchema2,
|
|
9253
|
+
database: DatabaseSchema,
|
|
9254
|
+
sql: import_zod6.z.string().min(1).max(MAX_SQL_LENGTH),
|
|
9255
|
+
params: RequiredSqlParamsSchema,
|
|
9256
|
+
acknowledgeDatabaseWideAuthority: import_zod6.z.literal(true).describe(SQL_WRITE_AUTHORITY_NOTICE)
|
|
9257
|
+
}).strict().superRefine((input, context) => {
|
|
9258
|
+
if (parseSingleDmlStatement(input.sql, input.params.length) === void 0) {
|
|
9259
|
+
context.addIssue({
|
|
9260
|
+
code: import_zod6.z.ZodIssueCode.custom,
|
|
9261
|
+
path: ["sql"],
|
|
9262
|
+
message: "SQL must parse as exactly one parameterized INSERT, UPDATE, or DELETE with one value per positional placeholder."
|
|
9263
|
+
});
|
|
9264
|
+
}
|
|
9265
|
+
});
|
|
9266
|
+
SqlLimitsOutputSchema = import_zod6.z.object({
|
|
9267
|
+
maxRows: import_zod6.z.number().int().positive(),
|
|
9268
|
+
maxBytes: import_zod6.z.number().int().positive(),
|
|
9269
|
+
enforcement: import_zod6.z.literal("node-requested-client-verified")
|
|
9270
|
+
}).strict();
|
|
9271
|
+
SqlSchemaInspectOutputSchema = import_zod6.z.object({
|
|
9272
|
+
space: import_zod6.z.string().min(1),
|
|
9273
|
+
database: import_zod6.z.string().min(1),
|
|
9274
|
+
objects: import_zod6.z.array(import_zod6.z.object({
|
|
9275
|
+
type: import_zod6.z.enum(["table", "view", "index", "trigger"]),
|
|
9276
|
+
name: import_zod6.z.string().min(1),
|
|
9277
|
+
tableName: import_zod6.z.string().min(1),
|
|
9278
|
+
sql: import_zod6.z.string().optional()
|
|
9279
|
+
}).strict()),
|
|
9280
|
+
count: import_zod6.z.number().int().nonnegative(),
|
|
9281
|
+
limits: SqlLimitsOutputSchema
|
|
9282
|
+
}).strict();
|
|
9283
|
+
SqlQueryOutputSchema = import_zod6.z.object({
|
|
9284
|
+
space: import_zod6.z.string().min(1),
|
|
9285
|
+
database: import_zod6.z.string().min(1),
|
|
9286
|
+
columns: import_zod6.z.array(import_zod6.z.string()),
|
|
9287
|
+
rows: import_zod6.z.array(import_zod6.z.array(SqlOutputValueSchema)),
|
|
9288
|
+
rowCount: import_zod6.z.number().int().nonnegative(),
|
|
9289
|
+
limits: SqlLimitsOutputSchema
|
|
9290
|
+
}).strict();
|
|
9291
|
+
SqlExecuteOutputSchema = import_zod6.z.object({
|
|
9292
|
+
space: import_zod6.z.string().min(1),
|
|
9293
|
+
database: import_zod6.z.string().min(1),
|
|
9294
|
+
statementType: import_zod6.z.enum(["insert", "update", "delete"]),
|
|
9295
|
+
changes: import_zod6.z.number().int().nonnegative(),
|
|
9296
|
+
lastInsertRowId: import_zod6.z.number().int().nullable(),
|
|
9297
|
+
authorityNotice: import_zod6.z.literal(SQL_WRITE_AUTHORITY_NOTICE)
|
|
9298
|
+
}).strict();
|
|
9299
|
+
AUTHENTICATED_POSTURES2 = [
|
|
9300
|
+
"owner-openkey",
|
|
9301
|
+
"delegate-session",
|
|
9302
|
+
"local-owner-key"
|
|
9303
|
+
];
|
|
9304
|
+
SQL_EXPOSURE = {
|
|
9305
|
+
cli: {
|
|
9306
|
+
status: "excluded",
|
|
9307
|
+
reason: "Existing SQL Commander commands remain the CLI surface."
|
|
9308
|
+
},
|
|
9309
|
+
mcp: { status: "required" },
|
|
9310
|
+
skill: { status: "required" },
|
|
9311
|
+
docs: { status: "required" }
|
|
9312
|
+
};
|
|
9313
|
+
SQL_SCHEMA_SENSITIVITY = {
|
|
9314
|
+
input: ["/database"],
|
|
9315
|
+
output: ["/objects"]
|
|
9316
|
+
};
|
|
9317
|
+
SQL_QUERY_SENSITIVITY = {
|
|
9318
|
+
input: ["/database", "/sql", "/params"],
|
|
9319
|
+
output: ["/columns", "/rows"]
|
|
9320
|
+
};
|
|
9321
|
+
SQL_EXECUTE_SENSITIVITY = {
|
|
9322
|
+
input: ["/database", "/sql", "/params"],
|
|
9323
|
+
output: ["/lastInsertRowId"]
|
|
9324
|
+
};
|
|
9325
|
+
sqlOperationDefinitions = [
|
|
9326
|
+
{
|
|
9327
|
+
id: "tinycloud.sql.schema.inspect",
|
|
9328
|
+
version: 1,
|
|
9329
|
+
title: "Inspect a TinyCloud SQLite schema",
|
|
9330
|
+
description: "List user tables, views, indexes, and triggers in one exact TinyCloud SQLite database using a fixed read-only query.",
|
|
9331
|
+
input: SqlTargetInputSchema,
|
|
9332
|
+
output: SqlSchemaInspectOutputSchema,
|
|
9333
|
+
effects: ["read"],
|
|
9334
|
+
runtime: "authenticated",
|
|
9335
|
+
postures: AUTHENTICATED_POSTURES2,
|
|
9336
|
+
exposure: SQL_EXPOSURE,
|
|
9337
|
+
sensitivity: SQL_SCHEMA_SENSITIVITY,
|
|
9338
|
+
authority: planSqlRead,
|
|
9339
|
+
execute: executeSqlSchemaInspect
|
|
9340
|
+
},
|
|
9341
|
+
{
|
|
9342
|
+
id: "tinycloud.sql.query",
|
|
9343
|
+
version: 1,
|
|
9344
|
+
title: "Query a TinyCloud SQLite database",
|
|
9345
|
+
description: "Run exactly one parser-approved SELECT against one exact TinyCloud SQLite database. Result limits are requested from the node and verified locally without silent truncation.",
|
|
9346
|
+
input: SqlQueryInputSchema,
|
|
9347
|
+
output: SqlQueryOutputSchema,
|
|
9348
|
+
effects: ["read"],
|
|
9349
|
+
runtime: "authenticated",
|
|
9350
|
+
postures: AUTHENTICATED_POSTURES2,
|
|
9351
|
+
exposure: SQL_EXPOSURE,
|
|
9352
|
+
sensitivity: SQL_QUERY_SENSITIVITY,
|
|
9353
|
+
invalidInputErrorCode: "SQL_QUERY_INVALID",
|
|
9354
|
+
authority: planSqlRead,
|
|
9355
|
+
execute: executeSqlQuery
|
|
9356
|
+
},
|
|
9357
|
+
{
|
|
9358
|
+
id: "tinycloud.sql.execute",
|
|
9359
|
+
version: 1,
|
|
9360
|
+
title: "Execute a TinyCloud SQLite DML statement",
|
|
9361
|
+
description: `Run exactly one parameterized INSERT, UPDATE, or DELETE against one exact TinyCloud SQLite database. ${SQL_WRITE_AUTHORITY_NOTICE}`,
|
|
9362
|
+
input: SqlExecuteInputSchema,
|
|
9363
|
+
output: SqlExecuteOutputSchema,
|
|
9364
|
+
effects: ["write", "destructive"],
|
|
9365
|
+
runtime: "authenticated",
|
|
9366
|
+
postures: AUTHENTICATED_POSTURES2,
|
|
9367
|
+
exposure: SQL_EXPOSURE,
|
|
9368
|
+
sensitivity: SQL_EXECUTE_SENSITIVITY,
|
|
9369
|
+
invalidInputErrorCode: "SQL_QUERY_INVALID",
|
|
9370
|
+
authority: planSqlWrite,
|
|
9371
|
+
execute: executeSqlDml
|
|
9372
|
+
}
|
|
9373
|
+
];
|
|
9374
|
+
}
|
|
9375
|
+
});
|
|
9376
|
+
|
|
8390
9377
|
// src/operations/status.ts
|
|
8391
9378
|
function createStatusDefinition(params) {
|
|
8392
9379
|
return {
|
|
@@ -8442,7 +9429,7 @@ async function inspectPinnedProfileStatus(context, _input) {
|
|
|
8442
9429
|
async function pinnedProfileExists(profile) {
|
|
8443
9430
|
try {
|
|
8444
9431
|
const storedProfile = await readProfile(profile);
|
|
8445
|
-
return
|
|
9432
|
+
return isRecord4(storedProfile);
|
|
8446
9433
|
} catch {
|
|
8447
9434
|
return false;
|
|
8448
9435
|
}
|
|
@@ -8462,7 +9449,7 @@ async function countLiveAdditionalDelegations(profile) {
|
|
|
8462
9449
|
}
|
|
8463
9450
|
function summarizeSession(session) {
|
|
8464
9451
|
if (session === null) return { present: false, expired: null, expiresAt: null };
|
|
8465
|
-
if (!
|
|
9452
|
+
if (!isRecord4(session)) throw new TypeError("Invalid session store.");
|
|
8466
9453
|
const expiry = extractSessionExpiry(session);
|
|
8467
9454
|
if (expiry === null) return { present: true, expired: null, expiresAt: null };
|
|
8468
9455
|
return {
|
|
@@ -8472,7 +9459,7 @@ function summarizeSession(session) {
|
|
|
8472
9459
|
};
|
|
8473
9460
|
}
|
|
8474
9461
|
function storedDelegationExpiry(entry) {
|
|
8475
|
-
if (!
|
|
9462
|
+
if (!isRecord4(entry) || !isRecord4(entry.delegation) || !("expiry" in entry.delegation)) {
|
|
8476
9463
|
throw new TypeError("Invalid stored delegation.");
|
|
8477
9464
|
}
|
|
8478
9465
|
return parseExpiry(entry.delegation.expiry);
|
|
@@ -8501,37 +9488,37 @@ function profileNotFound(profile) {
|
|
|
8501
9488
|
)
|
|
8502
9489
|
};
|
|
8503
9490
|
}
|
|
8504
|
-
function
|
|
9491
|
+
function isRecord4(value) {
|
|
8505
9492
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8506
9493
|
}
|
|
8507
|
-
var
|
|
9494
|
+
var import_zod7, StatusInputSchema, StatusOutputSchema, STATUS_POSTURES, STATUS_EXPOSURE, STATUS_SENSITIVITY, statusOperationDefinitions;
|
|
8508
9495
|
var init_status = __esm({
|
|
8509
9496
|
"src/operations/status.ts"() {
|
|
8510
9497
|
"use strict";
|
|
8511
|
-
|
|
9498
|
+
import_zod7 = require("zod");
|
|
8512
9499
|
init_errors();
|
|
8513
9500
|
init_state();
|
|
8514
|
-
StatusInputSchema =
|
|
8515
|
-
StatusOutputSchema =
|
|
8516
|
-
profile:
|
|
8517
|
-
host:
|
|
8518
|
-
posture:
|
|
9501
|
+
StatusInputSchema = import_zod7.z.object({}).strict();
|
|
9502
|
+
StatusOutputSchema = import_zod7.z.object({
|
|
9503
|
+
profile: import_zod7.z.string().min(1),
|
|
9504
|
+
host: import_zod7.z.string().min(1),
|
|
9505
|
+
posture: import_zod7.z.enum([
|
|
8519
9506
|
"owner-openkey",
|
|
8520
9507
|
"delegate-session",
|
|
8521
9508
|
"local-owner-key",
|
|
8522
9509
|
"unauthenticated"
|
|
8523
9510
|
]),
|
|
8524
|
-
operatorType:
|
|
8525
|
-
principalDid:
|
|
8526
|
-
sessionDid:
|
|
8527
|
-
ownerDid:
|
|
8528
|
-
space:
|
|
8529
|
-
session:
|
|
8530
|
-
present:
|
|
8531
|
-
expired:
|
|
8532
|
-
expiresAt:
|
|
9511
|
+
operatorType: import_zod7.z.enum(["human", "agent"]).optional(),
|
|
9512
|
+
principalDid: import_zod7.z.string().min(1).optional(),
|
|
9513
|
+
sessionDid: import_zod7.z.string().min(1).optional(),
|
|
9514
|
+
ownerDid: import_zod7.z.string().min(1).optional(),
|
|
9515
|
+
space: import_zod7.z.string().min(1).optional(),
|
|
9516
|
+
session: import_zod7.z.object({
|
|
9517
|
+
present: import_zod7.z.boolean(),
|
|
9518
|
+
expired: import_zod7.z.boolean().nullable(),
|
|
9519
|
+
expiresAt: import_zod7.z.string().datetime({ offset: true }).nullable()
|
|
8533
9520
|
}).strict(),
|
|
8534
|
-
liveAdditionalDelegationCount:
|
|
9521
|
+
liveAdditionalDelegationCount: import_zod7.z.number().int().nonnegative()
|
|
8535
9522
|
}).strict();
|
|
8536
9523
|
STATUS_POSTURES = [
|
|
8537
9524
|
"owner-openkey",
|
|
@@ -8572,6 +9559,7 @@ function registeredOperationDefinitions() {
|
|
|
8572
9559
|
...statusOperationDefinitions,
|
|
8573
9560
|
...authOperationDefinitions,
|
|
8574
9561
|
...explorationOperationDefinitions,
|
|
9562
|
+
...sqlOperationDefinitions,
|
|
8575
9563
|
...secretsGetOperationDefinitions
|
|
8576
9564
|
]);
|
|
8577
9565
|
return operationDefinitions;
|
|
@@ -8604,6 +9592,7 @@ var init_registry = __esm({
|
|
|
8604
9592
|
init_auth();
|
|
8605
9593
|
init_exploration();
|
|
8606
9594
|
init_secrets_get();
|
|
9595
|
+
init_sql();
|
|
8607
9596
|
init_status();
|
|
8608
9597
|
}
|
|
8609
9598
|
});
|
|
@@ -8683,9 +9672,9 @@ function isOperatorType(value) {
|
|
|
8683
9672
|
return value === "human" || value === "agent";
|
|
8684
9673
|
}
|
|
8685
9674
|
function isStoredProfile(value) {
|
|
8686
|
-
return
|
|
9675
|
+
return isRecord5(value) && isNonEmptyString(value.name) && isNonEmptyString(value.host) && typeof value.chainId === "number" && Number.isFinite(value.chainId) && isNonEmptyString(value.spaceName) && isNonEmptyString(value.did) && isNonEmptyString(value.createdAt) && isOptionalNonEmptyString(value.sessionDid) && isOptionalNonEmptyString(value.ownerDid) && isOptionalNonEmptyString(value.spaceId) && isOptionalPosture(value.posture) && isOptionalOperatorType(value.operatorType) && isOptionalAuthMethod(value.authMethod) && isOptionalNonEmptyString(value.defaultSpace) && isOptionalNonEmptyString(value.privateKey) && isOptionalNonEmptyString(value.address) && isOptionalNonEmptyString(value.openkeyHost);
|
|
8687
9676
|
}
|
|
8688
|
-
function
|
|
9677
|
+
function isRecord5(value) {
|
|
8689
9678
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8690
9679
|
}
|
|
8691
9680
|
function isNonEmptyString(value) {
|
|
@@ -8849,7 +9838,7 @@ function spaceForAuthenticatedPrincipal(principal2) {
|
|
|
8849
9838
|
function normalizeSession(session, key) {
|
|
8850
9839
|
const header = session.delegationHeader;
|
|
8851
9840
|
const jwk = hasPrivateParameter(session.jwk) ? session.jwk : key;
|
|
8852
|
-
if (!
|
|
9841
|
+
if (!isRecord6(header) || typeof header.Authorization !== "string" || typeof session.delegationCid !== "string" || typeof session.spaceId !== "string" || !hasPrivateParameter(jwk) || typeof session.verificationMethod !== "string") {
|
|
8853
9842
|
return void 0;
|
|
8854
9843
|
}
|
|
8855
9844
|
return {
|
|
@@ -8867,7 +9856,7 @@ function normalizeSession(session, key) {
|
|
|
8867
9856
|
}
|
|
8868
9857
|
function normalizeStoredDelegation(entry) {
|
|
8869
9858
|
const raw = entry.delegation;
|
|
8870
|
-
if (!
|
|
9859
|
+
if (!isRecord6(raw) || !isRecord6(raw.delegationHeader)) return void 0;
|
|
8871
9860
|
const expiry = parseExpiry2(raw.expiry);
|
|
8872
9861
|
if (expiry === void 0 || typeof raw.cid !== "string" || typeof raw.spaceId !== "string" || typeof raw.path !== "string" || !Array.isArray(raw.actions) || !raw.actions.every((action) => typeof action === "string") || typeof raw.delegateDID !== "string" || typeof raw.ownerAddress !== "string" || typeof raw.chainId !== "number" || typeof raw.delegationHeader.Authorization !== "string") {
|
|
8873
9862
|
return void 0;
|
|
@@ -8879,13 +9868,13 @@ function parseExpiry2(value) {
|
|
|
8879
9868
|
return expiry !== void 0 && !Number.isNaN(expiry.getTime()) ? expiry : void 0;
|
|
8880
9869
|
}
|
|
8881
9870
|
function hasPrivateParameter(value) {
|
|
8882
|
-
return
|
|
9871
|
+
return isRecord6(value) && typeof value.d === "string" && value.d.length > 0;
|
|
8883
9872
|
}
|
|
8884
9873
|
function normalizeDid(value) {
|
|
8885
9874
|
if (typeof value !== "string" || value.length === 0) return void 0;
|
|
8886
9875
|
return value.split("#", 1)[0];
|
|
8887
9876
|
}
|
|
8888
|
-
function
|
|
9877
|
+
function isRecord6(value) {
|
|
8889
9878
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8890
9879
|
}
|
|
8891
9880
|
function failed(context, error) {
|
|
@@ -9295,9 +10284,9 @@ async function invokeOperationWithLocalAuthorityRetry(operationId, operationVers
|
|
|
9295
10284
|
)
|
|
9296
10285
|
);
|
|
9297
10286
|
}
|
|
9298
|
-
const
|
|
9299
|
-
if (
|
|
9300
|
-
const operationContext =
|
|
10287
|
+
const runtimeContext3 = prepared.runtimeResolution.context;
|
|
10288
|
+
if (runtimeContext3.runtime === void 0) return internalOperationErrorResult(prepared);
|
|
10289
|
+
const operationContext = runtimeContext3;
|
|
9301
10290
|
let planned;
|
|
9302
10291
|
try {
|
|
9303
10292
|
planned = exactCapabilities2(await prepared.definition.authority(
|
|
@@ -9502,14 +10491,14 @@ async function prepareInvocation(operationId, operationVersion, invocationTarget
|
|
|
9502
10491
|
}
|
|
9503
10492
|
async function executePreparedInvocation(prepared, options = {}) {
|
|
9504
10493
|
const { operation, definition, parsedInput, runtimeResolution } = prepared;
|
|
9505
|
-
const
|
|
9506
|
-
const resolveSpace2 =
|
|
9507
|
-
|
|
9508
|
-
|
|
10494
|
+
const runtimeContext3 = runtimeResolution.context.runtime === void 0 ? void 0 : runtimeResolution.context;
|
|
10495
|
+
const resolveSpace2 = runtimeContext3 === void 0 ? void 0 : operationSpaceResolver(
|
|
10496
|
+
runtimeContext3.runtime.node,
|
|
10497
|
+
runtimeContext3.summary.space
|
|
9509
10498
|
);
|
|
9510
10499
|
try {
|
|
9511
10500
|
const planned = await definition.authority(
|
|
9512
|
-
|
|
10501
|
+
runtimeContext3 ?? runtimeResolution.context,
|
|
9513
10502
|
parsedInput.data
|
|
9514
10503
|
);
|
|
9515
10504
|
const required = exactCapabilities2(planned);
|
|
@@ -9524,12 +10513,12 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9524
10513
|
);
|
|
9525
10514
|
}
|
|
9526
10515
|
const evaluation = evaluateOperationAuthority(
|
|
9527
|
-
|
|
10516
|
+
runtimeContext3?.runtime.granted ?? [],
|
|
9528
10517
|
required,
|
|
9529
10518
|
resolveSpace2
|
|
9530
10519
|
);
|
|
9531
10520
|
if (!evaluation.satisfied) {
|
|
9532
|
-
if (
|
|
10521
|
+
if (runtimeContext3 === void 0) {
|
|
9533
10522
|
return errorResult(
|
|
9534
10523
|
operation,
|
|
9535
10524
|
runtimeResolution.context.summary,
|
|
@@ -9539,13 +10528,13 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9539
10528
|
if (options.deferAuthorityRequest) {
|
|
9540
10529
|
try {
|
|
9541
10530
|
const request = buildPermissionRequestArtifact({
|
|
9542
|
-
profile:
|
|
9543
|
-
host:
|
|
9544
|
-
sessionDid:
|
|
9545
|
-
posture:
|
|
9546
|
-
operatorType:
|
|
9547
|
-
...
|
|
9548
|
-
...
|
|
10531
|
+
profile: runtimeContext3.summary.profile,
|
|
10532
|
+
host: runtimeContext3.summary.host,
|
|
10533
|
+
sessionDid: runtimeContext3.summary.sessionDid,
|
|
10534
|
+
posture: runtimeContext3.summary.posture,
|
|
10535
|
+
operatorType: runtimeContext3.summary.operatorType ?? "human",
|
|
10536
|
+
...runtimeContext3.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext3.summary.ownerDid },
|
|
10537
|
+
...runtimeContext3.summary.space === void 0 ? {} : { spaceId: runtimeContext3.summary.space },
|
|
9549
10538
|
missing: evaluation.missing
|
|
9550
10539
|
});
|
|
9551
10540
|
return authorityRequiredResult(
|
|
@@ -9554,7 +10543,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9554
10543
|
parsedInput.data,
|
|
9555
10544
|
request,
|
|
9556
10545
|
evaluation.missing,
|
|
9557
|
-
|
|
10546
|
+
runtimeContext3.runtime.node
|
|
9558
10547
|
);
|
|
9559
10548
|
} catch {
|
|
9560
10549
|
return errorResult(
|
|
@@ -9565,7 +10554,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9565
10554
|
}
|
|
9566
10555
|
}
|
|
9567
10556
|
const authority = await persistAuthorityRequest(
|
|
9568
|
-
|
|
10557
|
+
runtimeContext3,
|
|
9569
10558
|
evaluation.missing
|
|
9570
10559
|
);
|
|
9571
10560
|
if (authority.status === "error") {
|
|
@@ -9581,7 +10570,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9581
10570
|
parsedInput.data,
|
|
9582
10571
|
authority.request,
|
|
9583
10572
|
authority.missing,
|
|
9584
|
-
|
|
10573
|
+
runtimeContext3.runtime.node
|
|
9585
10574
|
);
|
|
9586
10575
|
}
|
|
9587
10576
|
const outcome = await definition.execute(
|
|
@@ -9624,7 +10613,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9624
10613
|
)
|
|
9625
10614
|
);
|
|
9626
10615
|
}
|
|
9627
|
-
if (
|
|
10616
|
+
if (runtimeContext3 === void 0) {
|
|
9628
10617
|
return errorResult(
|
|
9629
10618
|
operation,
|
|
9630
10619
|
runtimeResolution.context.summary,
|
|
@@ -9634,13 +10623,13 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9634
10623
|
if (options.deferAuthorityRequest) {
|
|
9635
10624
|
try {
|
|
9636
10625
|
const request = buildPermissionRequestArtifact({
|
|
9637
|
-
profile:
|
|
9638
|
-
host:
|
|
9639
|
-
sessionDid:
|
|
9640
|
-
posture:
|
|
9641
|
-
operatorType:
|
|
9642
|
-
...
|
|
9643
|
-
...
|
|
10626
|
+
profile: runtimeContext3.summary.profile,
|
|
10627
|
+
host: runtimeContext3.summary.host,
|
|
10628
|
+
sessionDid: runtimeContext3.summary.sessionDid,
|
|
10629
|
+
posture: runtimeContext3.summary.posture,
|
|
10630
|
+
operatorType: runtimeContext3.summary.operatorType ?? "human",
|
|
10631
|
+
...runtimeContext3.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext3.summary.ownerDid },
|
|
10632
|
+
...runtimeContext3.summary.space === void 0 ? {} : { spaceId: runtimeContext3.summary.space },
|
|
9644
10633
|
missing: hinted
|
|
9645
10634
|
});
|
|
9646
10635
|
return authorityRequiredResult(
|
|
@@ -9649,7 +10638,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9649
10638
|
parsedInput.data,
|
|
9650
10639
|
request,
|
|
9651
10640
|
hinted,
|
|
9652
|
-
|
|
10641
|
+
runtimeContext3.runtime.node,
|
|
9653
10642
|
outcome.requiresCallerInput ?? false
|
|
9654
10643
|
);
|
|
9655
10644
|
} catch {
|
|
@@ -9661,7 +10650,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9661
10650
|
}
|
|
9662
10651
|
}
|
|
9663
10652
|
const authority = await persistAuthorityRequest(
|
|
9664
|
-
|
|
10653
|
+
runtimeContext3,
|
|
9665
10654
|
hinted,
|
|
9666
10655
|
true
|
|
9667
10656
|
);
|
|
@@ -9678,7 +10667,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9678
10667
|
parsedInput.data,
|
|
9679
10668
|
authority.request,
|
|
9680
10669
|
authority.missing,
|
|
9681
|
-
|
|
10670
|
+
runtimeContext3.runtime.node,
|
|
9682
10671
|
outcome.requiresCallerInput ?? false
|
|
9683
10672
|
);
|
|
9684
10673
|
}
|