@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.js
CHANGED
|
@@ -86,6 +86,14 @@ var init_errors = __esm({
|
|
|
86
86
|
"ENCRYPTION_NETWORK_UNRESOLVED",
|
|
87
87
|
"NODE_UNREACHABLE",
|
|
88
88
|
"NODE_ERROR",
|
|
89
|
+
"KV_NOT_FOUND",
|
|
90
|
+
"KV_PRECONDITION_FAILED",
|
|
91
|
+
"KV_CONFLICT",
|
|
92
|
+
"KV_RESPONSE_TOO_LARGE",
|
|
93
|
+
"SQL_QUERY_INVALID",
|
|
94
|
+
"SQL_EXECUTION_FAILED",
|
|
95
|
+
"SQL_RESULT_LIMIT_EXCEEDED",
|
|
96
|
+
"SQL_VALUE_UNSAFE",
|
|
89
97
|
"SECRET_READ_FAILED",
|
|
90
98
|
"SECRET_DECRYPT_FAILED",
|
|
91
99
|
"OUTPUT_INVALID",
|
|
@@ -1134,6 +1142,11 @@ function validateMigrationOptions(options) {
|
|
|
1134
1142
|
}
|
|
1135
1143
|
return null;
|
|
1136
1144
|
}
|
|
1145
|
+
function serializeSqlValues(values) {
|
|
1146
|
+
return values.map(
|
|
1147
|
+
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1137
1150
|
function migrationKey(namespace, id) {
|
|
1138
1151
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
1139
1152
|
}
|
|
@@ -2406,6 +2419,9 @@ var init_dist2 = __esm({
|
|
|
2406
2419
|
// KV-specific errors
|
|
2407
2420
|
KV_NOT_FOUND: "KV_NOT_FOUND",
|
|
2408
2421
|
KV_WRITE_FAILED: "KV_WRITE_FAILED",
|
|
2422
|
+
KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
|
|
2423
|
+
KV_CONFLICT: "KV_CONFLICT",
|
|
2424
|
+
KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
|
|
2409
2425
|
// SQL-specific errors
|
|
2410
2426
|
SQL_ERROR: "SQL_ERROR",
|
|
2411
2427
|
SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
|
|
@@ -3083,7 +3099,7 @@ var init_dist2 = __esm({
|
|
|
3083
3099
|
* @param signal - Optional abort signal
|
|
3084
3100
|
* @returns Fetch response
|
|
3085
3101
|
*/
|
|
3086
|
-
async invokeOperation(path, action, body, signal) {
|
|
3102
|
+
async invokeOperation(path, action, body, signal, extraHeaders) {
|
|
3087
3103
|
const session = this.context.session;
|
|
3088
3104
|
const headers = this.context.invoke(
|
|
3089
3105
|
session,
|
|
@@ -3091,9 +3107,10 @@ var init_dist2 = __esm({
|
|
|
3091
3107
|
path,
|
|
3092
3108
|
action
|
|
3093
3109
|
);
|
|
3110
|
+
const requestHeaders = Array.isArray(headers) ? [...headers, ...Object.entries(extraHeaders ?? {})] : { ...headers, ...extraHeaders };
|
|
3094
3111
|
return this.context.fetch(`${this.host}/invoke`, {
|
|
3095
3112
|
method: "POST",
|
|
3096
|
-
headers,
|
|
3113
|
+
headers: requestHeaders,
|
|
3097
3114
|
body,
|
|
3098
3115
|
signal: this.combineSignals(signal)
|
|
3099
3116
|
});
|
|
@@ -3275,13 +3292,21 @@ var init_dist2 = __esm({
|
|
|
3275
3292
|
if (!this.requireAuth()) {
|
|
3276
3293
|
return err(authRequiredError("kv"));
|
|
3277
3294
|
}
|
|
3295
|
+
if (options?.maxResponseBytes !== void 0 && (!Number.isSafeInteger(options.maxResponseBytes) || options.maxResponseBytes <= 0)) {
|
|
3296
|
+
return err(serviceError(
|
|
3297
|
+
ErrorCodes.INVALID_INPUT,
|
|
3298
|
+
"KV maxResponseBytes must be a positive safe integer",
|
|
3299
|
+
"kv"
|
|
3300
|
+
));
|
|
3301
|
+
}
|
|
3278
3302
|
const path = this.getFullPath(key, options?.prefix);
|
|
3279
3303
|
try {
|
|
3280
3304
|
const response = await this.invokeOperation(
|
|
3281
3305
|
path,
|
|
3282
3306
|
KVAction.GET,
|
|
3283
3307
|
void 0,
|
|
3284
|
-
options?.signal
|
|
3308
|
+
options?.signal,
|
|
3309
|
+
options?.maxResponseBytes === void 0 ? void 0 : { "x-tinycloud-max-response-bytes": String(options.maxResponseBytes) }
|
|
3285
3310
|
);
|
|
3286
3311
|
if (!response.ok) {
|
|
3287
3312
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -3299,6 +3324,14 @@ var init_dist2 = __esm({
|
|
|
3299
3324
|
return this.classifyNotFound(response, key);
|
|
3300
3325
|
}
|
|
3301
3326
|
const errorText = await response.text();
|
|
3327
|
+
if (response.status === 413) {
|
|
3328
|
+
return err(serviceError(
|
|
3329
|
+
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
3330
|
+
`KV value at key "${key}" exceeds the requested response limit`,
|
|
3331
|
+
"kv",
|
|
3332
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3333
|
+
));
|
|
3334
|
+
}
|
|
3302
3335
|
return err(
|
|
3303
3336
|
serviceError(
|
|
3304
3337
|
ErrorCodes.NETWORK_ERROR,
|
|
@@ -3330,6 +3363,13 @@ var init_dist2 = __esm({
|
|
|
3330
3363
|
if (!this.requireAuth()) {
|
|
3331
3364
|
return err(authRequiredError("kv"));
|
|
3332
3365
|
}
|
|
3366
|
+
if (options?.ifMatch !== void 0 && options.ifNoneMatch !== void 0) {
|
|
3367
|
+
return err(serviceError(
|
|
3368
|
+
ErrorCodes.INVALID_INPUT,
|
|
3369
|
+
"KV put cannot combine ifMatch and ifNoneMatch",
|
|
3370
|
+
"kv"
|
|
3371
|
+
));
|
|
3372
|
+
}
|
|
3333
3373
|
const path = this.getFullPath(key, options?.prefix);
|
|
3334
3374
|
const body = this.serializePutValue(value, options?.contentType);
|
|
3335
3375
|
try {
|
|
@@ -3337,7 +3377,11 @@ var init_dist2 = __esm({
|
|
|
3337
3377
|
path,
|
|
3338
3378
|
KVAction.PUT,
|
|
3339
3379
|
body,
|
|
3340
|
-
options?.signal
|
|
3380
|
+
options?.signal,
|
|
3381
|
+
{
|
|
3382
|
+
...options?.ifMatch === void 0 ? {} : { "if-match": options.ifMatch },
|
|
3383
|
+
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
3384
|
+
}
|
|
3341
3385
|
);
|
|
3342
3386
|
if (!response.ok) {
|
|
3343
3387
|
if (response.status === 401) {
|
|
@@ -3350,6 +3394,22 @@ var init_dist2 = __esm({
|
|
|
3350
3394
|
}));
|
|
3351
3395
|
}
|
|
3352
3396
|
const errorText = await response.text();
|
|
3397
|
+
if (response.status === 412) {
|
|
3398
|
+
return err(serviceError(
|
|
3399
|
+
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
3400
|
+
`KV precondition failed for key "${key}"`,
|
|
3401
|
+
"kv",
|
|
3402
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3403
|
+
));
|
|
3404
|
+
}
|
|
3405
|
+
if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
|
|
3406
|
+
return err(serviceError(
|
|
3407
|
+
ErrorCodes.KV_CONFLICT,
|
|
3408
|
+
`Concurrent KV update conflicted for key "${key}"`,
|
|
3409
|
+
"kv",
|
|
3410
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3411
|
+
));
|
|
3412
|
+
}
|
|
3353
3413
|
const quotaError = this.handleQuotaErrorResponse(
|
|
3354
3414
|
response,
|
|
3355
3415
|
errorText,
|
|
@@ -3485,6 +3545,13 @@ var init_dist2 = __esm({
|
|
|
3485
3545
|
if (!this.requireAuth()) {
|
|
3486
3546
|
return err(authRequiredError("kv"));
|
|
3487
3547
|
}
|
|
3548
|
+
if (options?.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 1e3)) {
|
|
3549
|
+
return err(serviceError(
|
|
3550
|
+
ErrorCodes.INVALID_INPUT,
|
|
3551
|
+
"KV list limit must be an integer from 1 through 1000",
|
|
3552
|
+
"kv"
|
|
3553
|
+
));
|
|
3554
|
+
}
|
|
3488
3555
|
let listPath = options?.prefix ?? this._config.prefix ?? "";
|
|
3489
3556
|
if (options?.path) {
|
|
3490
3557
|
listPath = listPath ? `${listPath}/${options.path}` : options.path;
|
|
@@ -3494,7 +3561,8 @@ var init_dist2 = __esm({
|
|
|
3494
3561
|
listPath,
|
|
3495
3562
|
KVAction.LIST,
|
|
3496
3563
|
void 0,
|
|
3497
|
-
options?.signal
|
|
3564
|
+
options?.signal,
|
|
3565
|
+
options?.limit === void 0 ? void 0 : { "x-tinycloud-limit": String(options.limit) }
|
|
3498
3566
|
);
|
|
3499
3567
|
if (!response.ok) {
|
|
3500
3568
|
if (response.status === 401) {
|
|
@@ -3524,7 +3592,10 @@ var init_dist2 = __esm({
|
|
|
3524
3592
|
(key) => key.startsWith(prefixWithSlash) ? key.slice(prefixWithSlash.length) : key
|
|
3525
3593
|
);
|
|
3526
3594
|
}
|
|
3527
|
-
return ok({
|
|
3595
|
+
return ok({
|
|
3596
|
+
keys,
|
|
3597
|
+
...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" }
|
|
3598
|
+
});
|
|
3528
3599
|
} catch (error) {
|
|
3529
3600
|
return err(wrapError("kv", error));
|
|
3530
3601
|
}
|
|
@@ -3544,7 +3615,8 @@ var init_dist2 = __esm({
|
|
|
3544
3615
|
path,
|
|
3545
3616
|
KVAction.DELETE,
|
|
3546
3617
|
void 0,
|
|
3547
|
-
options?.signal
|
|
3618
|
+
options?.signal,
|
|
3619
|
+
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
3548
3620
|
);
|
|
3549
3621
|
if (!response.ok) {
|
|
3550
3622
|
if (response.status === 401) {
|
|
@@ -3560,6 +3632,22 @@ var init_dist2 = __esm({
|
|
|
3560
3632
|
return this.classifyNotFound(response, key);
|
|
3561
3633
|
}
|
|
3562
3634
|
const errorText = await response.text();
|
|
3635
|
+
if (response.status === 412) {
|
|
3636
|
+
return err(serviceError(
|
|
3637
|
+
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
3638
|
+
`KV precondition failed for key "${key}"`,
|
|
3639
|
+
"kv",
|
|
3640
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3641
|
+
));
|
|
3642
|
+
}
|
|
3643
|
+
if (response.status === 503 && options?.ifMatch !== void 0) {
|
|
3644
|
+
return err(serviceError(
|
|
3645
|
+
ErrorCodes.KV_CONFLICT,
|
|
3646
|
+
`Concurrent KV delete conflicted for key "${key}"`,
|
|
3647
|
+
"kv",
|
|
3648
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
3649
|
+
));
|
|
3650
|
+
}
|
|
3563
3651
|
return err(
|
|
3564
3652
|
serviceError(
|
|
3565
3653
|
ErrorCodes.NETWORK_ERROR,
|
|
@@ -3569,7 +3657,10 @@ var init_dist2 = __esm({
|
|
|
3569
3657
|
)
|
|
3570
3658
|
);
|
|
3571
3659
|
}
|
|
3572
|
-
return ok(
|
|
3660
|
+
return ok({
|
|
3661
|
+
data: void 0,
|
|
3662
|
+
headers: this.createResponseHeaders(response.headers)
|
|
3663
|
+
});
|
|
3573
3664
|
} catch (error) {
|
|
3574
3665
|
return err(wrapError("kv", error));
|
|
3575
3666
|
}
|
|
@@ -3841,10 +3932,17 @@ var init_dist2 = __esm({
|
|
|
3841
3932
|
return err(authRequiredError("sql"));
|
|
3842
3933
|
}
|
|
3843
3934
|
try {
|
|
3935
|
+
const body = {
|
|
3936
|
+
action: "query",
|
|
3937
|
+
sql,
|
|
3938
|
+
params: serializeSqlValues(params ?? [])
|
|
3939
|
+
};
|
|
3940
|
+
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
3941
|
+
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
3844
3942
|
const response = await this.invokeSQL(
|
|
3845
3943
|
dbName,
|
|
3846
3944
|
this.actionForSql(sql, SQLAction.READ),
|
|
3847
|
-
|
|
3945
|
+
body,
|
|
3848
3946
|
options?.signal
|
|
3849
3947
|
);
|
|
3850
3948
|
if (!response.ok) {
|
|
@@ -3866,7 +3964,7 @@ var init_dist2 = __esm({
|
|
|
3866
3964
|
const body = {
|
|
3867
3965
|
action: "execute",
|
|
3868
3966
|
sql,
|
|
3869
|
-
params: params ?? []
|
|
3967
|
+
params: serializeSqlValues(params ?? [])
|
|
3870
3968
|
};
|
|
3871
3969
|
if (options?.schema) {
|
|
3872
3970
|
body.schema = options.schema;
|
|
@@ -7831,7 +7929,7 @@ async function planAccountRegistryRead(context, path) {
|
|
|
7831
7929
|
}];
|
|
7832
7930
|
}
|
|
7833
7931
|
async function planKvList(context, input) {
|
|
7834
|
-
const space =
|
|
7932
|
+
const space = resolveGenericKvSpace(context, input.space);
|
|
7835
7933
|
return [{
|
|
7836
7934
|
service: "tinycloud.kv",
|
|
7837
7935
|
space,
|
|
@@ -7840,7 +7938,7 @@ async function planKvList(context, input) {
|
|
|
7840
7938
|
}];
|
|
7841
7939
|
}
|
|
7842
7940
|
async function planKvGet(context, input) {
|
|
7843
|
-
const space =
|
|
7941
|
+
const space = resolveGenericKvSpace(context, input.space);
|
|
7844
7942
|
return [{
|
|
7845
7943
|
service: "tinycloud.kv",
|
|
7846
7944
|
space,
|
|
@@ -7848,12 +7946,21 @@ async function planKvGet(context, input) {
|
|
|
7848
7946
|
actions: ["tinycloud.kv/get"]
|
|
7849
7947
|
}];
|
|
7850
7948
|
}
|
|
7949
|
+
async function planExactKv(context, requestedSpace, key, action) {
|
|
7950
|
+
return [{
|
|
7951
|
+
service: "tinycloud.kv",
|
|
7952
|
+
space: resolveGenericKvSpace(context, requestedSpace),
|
|
7953
|
+
path: key,
|
|
7954
|
+
actions: [action]
|
|
7955
|
+
}];
|
|
7956
|
+
}
|
|
7851
7957
|
async function executeAccountSpacesList(context, _input) {
|
|
7852
7958
|
try {
|
|
7853
7959
|
const entries = await readAccountRegistry(context, "spaces/");
|
|
7854
|
-
if (!entries.ok) return
|
|
7960
|
+
if (!entries.ok) return entries.outcome;
|
|
7855
7961
|
const spaces = entries.records.map(({ key, value }) => projectAccountSpace(key, value)).sort((left, right) => left.name.localeCompare(right.name) || left.spaceId.localeCompare(right.spaceId));
|
|
7856
|
-
|
|
7962
|
+
const output = { spaces, count: spaces.length };
|
|
7963
|
+
return accountRegistryOutput(output);
|
|
7857
7964
|
} catch {
|
|
7858
7965
|
return nodeFailure("list account spaces");
|
|
7859
7966
|
}
|
|
@@ -7861,9 +7968,10 @@ async function executeAccountSpacesList(context, _input) {
|
|
|
7861
7968
|
async function executeAccountApplicationsList(context, _input) {
|
|
7862
7969
|
try {
|
|
7863
7970
|
const entries = await readAccountRegistry(context, "applications/");
|
|
7864
|
-
if (!entries.ok) return
|
|
7971
|
+
if (!entries.ok) return entries.outcome;
|
|
7865
7972
|
const applications = entries.records.map(({ key, value }) => projectAccountApplication(key, value)).sort((left, right) => left.appId.localeCompare(right.appId));
|
|
7866
|
-
|
|
7973
|
+
const output = { applications, count: applications.length };
|
|
7974
|
+
return accountRegistryOutput(output);
|
|
7867
7975
|
} catch {
|
|
7868
7976
|
return nodeFailure("list account applications");
|
|
7869
7977
|
}
|
|
@@ -7871,15 +7979,22 @@ async function executeAccountApplicationsList(context, _input) {
|
|
|
7871
7979
|
async function executeKvList(context, input) {
|
|
7872
7980
|
try {
|
|
7873
7981
|
const runtime = runtimeContext(context);
|
|
7874
|
-
const space =
|
|
7875
|
-
const result = await
|
|
7876
|
-
input.prefix === void 0 ?
|
|
7877
|
-
|
|
7982
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
7983
|
+
const result = await genericKv(runtime, space).list({
|
|
7984
|
+
...input.prefix === void 0 ? {} : { prefix: input.prefix },
|
|
7985
|
+
limit: input.limit ?? DEFAULT_KV_LIST_LIMIT
|
|
7986
|
+
});
|
|
7878
7987
|
if (!result.ok) return nodeFailure("list KV keys");
|
|
7879
7988
|
const keys = [...result.data.keys];
|
|
7880
7989
|
return {
|
|
7881
7990
|
status: "ok",
|
|
7882
|
-
output: {
|
|
7991
|
+
output: {
|
|
7992
|
+
space,
|
|
7993
|
+
prefix: input.prefix ?? "",
|
|
7994
|
+
keys,
|
|
7995
|
+
count: keys.length,
|
|
7996
|
+
truncated: result.data.truncated ?? false
|
|
7997
|
+
}
|
|
7883
7998
|
};
|
|
7884
7999
|
} catch (error) {
|
|
7885
8000
|
if (error instanceof OperationInvocationError) {
|
|
@@ -7891,10 +8006,18 @@ async function executeKvList(context, input) {
|
|
|
7891
8006
|
async function executeKvGet(context, input) {
|
|
7892
8007
|
try {
|
|
7893
8008
|
const runtime = runtimeContext(context);
|
|
7894
|
-
const space =
|
|
7895
|
-
const result = await
|
|
7896
|
-
|
|
7897
|
-
|
|
8009
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8010
|
+
const result = await genericKv(runtime, space).get(input.key, {
|
|
8011
|
+
binary: true,
|
|
8012
|
+
maxResponseBytes: MAX_KV_VALUE_BYTES
|
|
8013
|
+
});
|
|
8014
|
+
if (!result.ok) return kvFailure(result.error, "read the KV value");
|
|
8015
|
+
const bytes = result.data.data;
|
|
8016
|
+
if (bytes.byteLength > MAX_KV_VALUE_BYTES) {
|
|
8017
|
+
return kvFailure({ code: "KV_RESPONSE_TOO_LARGE" }, "read the KV value");
|
|
8018
|
+
}
|
|
8019
|
+
const encoded = encodeKvValue(bytes, input.representation ?? "base64");
|
|
8020
|
+
if (!encoded.ok) return encoded.outcome;
|
|
7898
8021
|
return {
|
|
7899
8022
|
status: "ok",
|
|
7900
8023
|
output: {
|
|
@@ -7902,12 +8025,8 @@ async function executeKvGet(context, input) {
|
|
|
7902
8025
|
key: input.key,
|
|
7903
8026
|
value: encoded.value,
|
|
7904
8027
|
encoding: encoded.encoding,
|
|
7905
|
-
metadata:
|
|
7906
|
-
|
|
7907
|
-
...result.data.headers.contentType === void 0 ? {} : { contentType: result.data.headers.contentType },
|
|
7908
|
-
...result.data.headers.lastModified === void 0 ? {} : { lastModified: result.data.headers.lastModified },
|
|
7909
|
-
...result.data.headers.contentLength === void 0 ? {} : { contentLength: result.data.headers.contentLength }
|
|
7910
|
-
}
|
|
8028
|
+
metadata: projectKvMetadata(result.data.headers),
|
|
8029
|
+
byteLength: bytes.byteLength
|
|
7911
8030
|
}
|
|
7912
8031
|
};
|
|
7913
8032
|
} catch (error) {
|
|
@@ -7917,6 +8036,66 @@ async function executeKvGet(context, input) {
|
|
|
7917
8036
|
return nodeFailure("read the KV value");
|
|
7918
8037
|
}
|
|
7919
8038
|
}
|
|
8039
|
+
async function executeKvHead(context, input) {
|
|
8040
|
+
try {
|
|
8041
|
+
const runtime = runtimeContext(context);
|
|
8042
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8043
|
+
const result = await genericKv(runtime, space).head(input.key);
|
|
8044
|
+
if (!result.ok) return kvFailure(result.error, "read KV metadata");
|
|
8045
|
+
return { status: "ok", output: { space, key: input.key, metadata: projectKvMetadata(result.data.headers) } };
|
|
8046
|
+
} catch (error) {
|
|
8047
|
+
return caughtKvFailure(error, "read KV metadata");
|
|
8048
|
+
}
|
|
8049
|
+
}
|
|
8050
|
+
async function executeKvPut(context, input) {
|
|
8051
|
+
try {
|
|
8052
|
+
const runtime = runtimeContext(context);
|
|
8053
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8054
|
+
const decoded = decodeKvPutContent(input.content);
|
|
8055
|
+
if (decoded === void 0 || decoded.byteLength > MAX_KV_VALUE_BYTES) {
|
|
8056
|
+
return { status: "error", error: operationError("INPUT_INVALID", "The KV content is invalid or too large.") };
|
|
8057
|
+
}
|
|
8058
|
+
const result = await genericKv(runtime, space).put(input.key, decoded.bytes, {
|
|
8059
|
+
contentType: input.contentType ?? decoded.contentType,
|
|
8060
|
+
...input.mode === "create" ? { ifNoneMatch: "*" } : {},
|
|
8061
|
+
...input.mode === "replace" ? { ifMatch: input.etag } : {}
|
|
8062
|
+
});
|
|
8063
|
+
if (!result.ok) return kvFailure(result.error, "write the KV value");
|
|
8064
|
+
return {
|
|
8065
|
+
status: "ok",
|
|
8066
|
+
output: {
|
|
8067
|
+
space,
|
|
8068
|
+
key: input.key,
|
|
8069
|
+
mode: input.mode,
|
|
8070
|
+
byteLength: decoded.byteLength,
|
|
8071
|
+
metadata: projectKvMetadata(result.data.headers)
|
|
8072
|
+
}
|
|
8073
|
+
};
|
|
8074
|
+
} catch (error) {
|
|
8075
|
+
return caughtKvFailure(error, "write the KV value");
|
|
8076
|
+
}
|
|
8077
|
+
}
|
|
8078
|
+
async function executeKvDelete(context, input) {
|
|
8079
|
+
try {
|
|
8080
|
+
const runtime = runtimeContext(context);
|
|
8081
|
+
const space = resolveGenericKvSpace(runtime, input.space);
|
|
8082
|
+
const result = await genericKv(runtime, space).delete(input.key, {
|
|
8083
|
+
...input.etag === void 0 ? {} : { ifMatch: input.etag }
|
|
8084
|
+
});
|
|
8085
|
+
if (!result.ok) return kvFailure(result.error, "delete the KV value");
|
|
8086
|
+
return {
|
|
8087
|
+
status: "ok",
|
|
8088
|
+
output: {
|
|
8089
|
+
space,
|
|
8090
|
+
key: input.key,
|
|
8091
|
+
deleted: true,
|
|
8092
|
+
...result.data.headers.etag === void 0 ? {} : { etag: result.data.headers.etag }
|
|
8093
|
+
}
|
|
8094
|
+
};
|
|
8095
|
+
} catch (error) {
|
|
8096
|
+
return caughtKvFailure(error, "delete the KV value");
|
|
8097
|
+
}
|
|
8098
|
+
}
|
|
7920
8099
|
function runtimeContext(context) {
|
|
7921
8100
|
if (context.runtime === void 0) {
|
|
7922
8101
|
throw new TypeError("Authenticated operation runtime is unavailable.");
|
|
@@ -7926,15 +8105,19 @@ function runtimeContext(context) {
|
|
|
7926
8105
|
function runtimeNode(context) {
|
|
7927
8106
|
return runtimeContext(context).runtime.node;
|
|
7928
8107
|
}
|
|
8108
|
+
function genericKv(context, space) {
|
|
8109
|
+
return runtimeNode(context).kvForSpace(space);
|
|
8110
|
+
}
|
|
7929
8111
|
function resolveSpace(context, space) {
|
|
7930
8112
|
return operationSpaceResolver(context.runtime.node, context.summary.space)(space);
|
|
7931
8113
|
}
|
|
7932
|
-
function
|
|
8114
|
+
function resolveGenericKvSpace(context, space) {
|
|
7933
8115
|
const resolved = resolveSpace(context, space);
|
|
7934
|
-
|
|
8116
|
+
const protectedName = resolved.split(":").at(-1)?.toLowerCase();
|
|
8117
|
+
if (protectedName === "secrets" || protectedName === "account") {
|
|
7935
8118
|
throw new OperationInvocationError(operationError(
|
|
7936
8119
|
"INPUT_INVALID",
|
|
7937
|
-
"Generic KV operations cannot access
|
|
8120
|
+
"Generic KV operations cannot access TinyCloud account or secrets spaces."
|
|
7938
8121
|
));
|
|
7939
8122
|
}
|
|
7940
8123
|
return resolved;
|
|
@@ -7943,13 +8126,57 @@ async function readAccountRegistry(context, prefix) {
|
|
|
7943
8126
|
const runtime = runtimeContext(context);
|
|
7944
8127
|
const accountSpace = resolveSpace(runtime, "account");
|
|
7945
8128
|
const kv = runtimeNode(runtime).kvForSpace(accountSpace);
|
|
7946
|
-
const listed = await kv.list({ prefix });
|
|
7947
|
-
if (!listed.ok) return { ok: false };
|
|
8129
|
+
const listed = await kv.list({ prefix, limit: MAX_ACCOUNT_REGISTRY_RECORDS });
|
|
8130
|
+
if (!listed.ok) return { ok: false, outcome: nodeFailure("list the account registry") };
|
|
8131
|
+
if (listed.data.truncated === true) {
|
|
8132
|
+
return {
|
|
8133
|
+
ok: false,
|
|
8134
|
+
outcome: {
|
|
8135
|
+
status: "error",
|
|
8136
|
+
error: operationError(
|
|
8137
|
+
"OUTPUT_INVALID",
|
|
8138
|
+
`The TinyCloud account registry exceeds the ${MAX_ACCOUNT_REGISTRY_RECORDS}-record exploration limit.`
|
|
8139
|
+
)
|
|
8140
|
+
}
|
|
8141
|
+
};
|
|
8142
|
+
}
|
|
7948
8143
|
const records = [];
|
|
8144
|
+
let totalBytes = 0;
|
|
7949
8145
|
for (const key of listed.data.keys) {
|
|
7950
|
-
const loaded = await kv.get(key
|
|
7951
|
-
|
|
7952
|
-
|
|
8146
|
+
const loaded = await kv.get(key, {
|
|
8147
|
+
binary: true,
|
|
8148
|
+
maxResponseBytes: MAX_KV_VALUE_BYTES
|
|
8149
|
+
});
|
|
8150
|
+
if (!loaded.ok) {
|
|
8151
|
+
return { ok: false, outcome: kvFailure(loaded.error, "read the account registry") };
|
|
8152
|
+
}
|
|
8153
|
+
const bytes = loaded.data.data;
|
|
8154
|
+
totalBytes += bytes.byteLength;
|
|
8155
|
+
if (bytes.byteLength > MAX_KV_VALUE_BYTES || totalBytes > MAX_ACCOUNT_REGISTRY_BYTES) {
|
|
8156
|
+
return {
|
|
8157
|
+
ok: false,
|
|
8158
|
+
outcome: {
|
|
8159
|
+
status: "error",
|
|
8160
|
+
error: operationError(
|
|
8161
|
+
"KV_RESPONSE_TOO_LARGE",
|
|
8162
|
+
`The TinyCloud account registry exceeds the ${MAX_ACCOUNT_REGISTRY_BYTES}-byte exploration limit.`
|
|
8163
|
+
)
|
|
8164
|
+
}
|
|
8165
|
+
};
|
|
8166
|
+
}
|
|
8167
|
+
try {
|
|
8168
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
8169
|
+
if (!isRecord2(value)) throw new TypeError("Account registry values must be JSON objects.");
|
|
8170
|
+
records.push({ key, value });
|
|
8171
|
+
} catch {
|
|
8172
|
+
return {
|
|
8173
|
+
ok: false,
|
|
8174
|
+
outcome: {
|
|
8175
|
+
status: "error",
|
|
8176
|
+
error: operationError("OUTPUT_INVALID", "The TinyCloud account registry contains an invalid record.")
|
|
8177
|
+
}
|
|
8178
|
+
};
|
|
8179
|
+
}
|
|
7953
8180
|
}
|
|
7954
8181
|
return { ok: true, records };
|
|
7955
8182
|
}
|
|
@@ -7995,15 +8222,110 @@ function stringField2(record, ...keys) {
|
|
|
7995
8222
|
function isRecord2(value) {
|
|
7996
8223
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7997
8224
|
}
|
|
7998
|
-
function encodeKvValue(value) {
|
|
7999
|
-
if (
|
|
8000
|
-
return { value: Buffer.from(value).toString("base64"), encoding: "base64" };
|
|
8225
|
+
function encodeKvValue(value, representation) {
|
|
8226
|
+
if (representation === "base64") {
|
|
8227
|
+
return { ok: true, value: Buffer.from(value).toString("base64"), encoding: "base64" };
|
|
8228
|
+
}
|
|
8229
|
+
let text;
|
|
8230
|
+
try {
|
|
8231
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
8232
|
+
} catch {
|
|
8233
|
+
return {
|
|
8234
|
+
ok: false,
|
|
8235
|
+
outcome: { status: "error", error: operationError("OUTPUT_INVALID", "The KV value is not valid UTF-8.") }
|
|
8236
|
+
};
|
|
8237
|
+
}
|
|
8238
|
+
if (representation === "text") return { ok: true, value: text, encoding: "text" };
|
|
8239
|
+
try {
|
|
8240
|
+
const parsed = JsonValueSchema.safeParse(JSON.parse(text));
|
|
8241
|
+
if (!parsed.success) {
|
|
8242
|
+
return {
|
|
8243
|
+
ok: false,
|
|
8244
|
+
outcome: {
|
|
8245
|
+
status: "error",
|
|
8246
|
+
error: operationError(
|
|
8247
|
+
"OUTPUT_INVALID",
|
|
8248
|
+
"The KV JSON contains a number that cannot be represented safely."
|
|
8249
|
+
)
|
|
8250
|
+
}
|
|
8251
|
+
};
|
|
8252
|
+
}
|
|
8253
|
+
return { ok: true, value: parsed.data, encoding: "json" };
|
|
8254
|
+
} catch {
|
|
8255
|
+
return {
|
|
8256
|
+
ok: false,
|
|
8257
|
+
outcome: { status: "error", error: operationError("OUTPUT_INVALID", "The KV value is not valid JSON.") }
|
|
8258
|
+
};
|
|
8259
|
+
}
|
|
8260
|
+
}
|
|
8261
|
+
function decodeKvPutContent(content) {
|
|
8262
|
+
let bytes;
|
|
8263
|
+
let contentType;
|
|
8264
|
+
if (content.encoding === "utf8") {
|
|
8265
|
+
bytes = new TextEncoder().encode(content.value);
|
|
8266
|
+
contentType = "text/plain;charset=UTF-8";
|
|
8267
|
+
} else if (content.encoding === "json") {
|
|
8268
|
+
bytes = new TextEncoder().encode(JSON.stringify(content.value));
|
|
8269
|
+
contentType = "application/json";
|
|
8270
|
+
} else {
|
|
8271
|
+
if (!isCanonicalBase64(content.value)) return void 0;
|
|
8272
|
+
bytes = new Uint8Array(Buffer.from(content.value, "base64"));
|
|
8273
|
+
contentType = "application/octet-stream";
|
|
8274
|
+
}
|
|
8275
|
+
return { bytes, byteLength: bytes.byteLength, contentType };
|
|
8276
|
+
}
|
|
8277
|
+
function isCanonicalBase64(value) {
|
|
8278
|
+
if (value.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
8279
|
+
return false;
|
|
8001
8280
|
}
|
|
8281
|
+
return Buffer.from(value, "base64").toString("base64") === value;
|
|
8282
|
+
}
|
|
8283
|
+
function projectKvMetadata(headers) {
|
|
8002
8284
|
return {
|
|
8003
|
-
|
|
8004
|
-
|
|
8285
|
+
...headers.etag === void 0 ? {} : { etag: headers.etag },
|
|
8286
|
+
...headers.contentType === void 0 ? {} : { contentType: headers.contentType },
|
|
8287
|
+
...headers.lastModified === void 0 ? {} : { lastModified: headers.lastModified },
|
|
8288
|
+
...headers.contentLength === void 0 ? {} : { contentLength: headers.contentLength }
|
|
8005
8289
|
};
|
|
8006
8290
|
}
|
|
8291
|
+
function caughtKvFailure(error, action) {
|
|
8292
|
+
if (error instanceof OperationInvocationError) return { status: "error", error: error.operationError };
|
|
8293
|
+
return nodeFailure(action);
|
|
8294
|
+
}
|
|
8295
|
+
function accountRegistryOutput(output) {
|
|
8296
|
+
if (Buffer.byteLength(JSON.stringify(output), "utf8") > MAX_ACCOUNT_REGISTRY_BYTES) {
|
|
8297
|
+
return {
|
|
8298
|
+
status: "error",
|
|
8299
|
+
error: operationError(
|
|
8300
|
+
"KV_RESPONSE_TOO_LARGE",
|
|
8301
|
+
`The TinyCloud account registry exceeds the ${MAX_ACCOUNT_REGISTRY_BYTES}-byte exploration limit.`
|
|
8302
|
+
)
|
|
8303
|
+
};
|
|
8304
|
+
}
|
|
8305
|
+
return { status: "ok", output };
|
|
8306
|
+
}
|
|
8307
|
+
function kvFailure(error, action) {
|
|
8308
|
+
if (error.code === "KV_NOT_FOUND") {
|
|
8309
|
+
return { status: "error", error: operationError("KV_NOT_FOUND", "The TinyCloud KV key was not found.") };
|
|
8310
|
+
}
|
|
8311
|
+
if (error.code === "KV_PRECONDITION_FAILED") {
|
|
8312
|
+
return { status: "error", error: operationError("KV_PRECONDITION_FAILED", "The TinyCloud KV object changed or already exists.") };
|
|
8313
|
+
}
|
|
8314
|
+
if (error.code === "KV_CONFLICT") {
|
|
8315
|
+
return {
|
|
8316
|
+
status: "error",
|
|
8317
|
+
error: operationError(
|
|
8318
|
+
"KV_CONFLICT",
|
|
8319
|
+
"A database serialization conflict prevented the conditional KV mutation; re-read the key state, which may still be absent, before deciding whether to retry.",
|
|
8320
|
+
{ retryable: true }
|
|
8321
|
+
)
|
|
8322
|
+
};
|
|
8323
|
+
}
|
|
8324
|
+
if (error.code === "KV_RESPONSE_TOO_LARGE") {
|
|
8325
|
+
return { status: "error", error: operationError("KV_RESPONSE_TOO_LARGE", `The TinyCloud KV value exceeds ${MAX_KV_VALUE_BYTES} bytes.`) };
|
|
8326
|
+
}
|
|
8327
|
+
return nodeFailure(action);
|
|
8328
|
+
}
|
|
8007
8329
|
function nodeFailure(action) {
|
|
8008
8330
|
return {
|
|
8009
8331
|
status: "error",
|
|
@@ -8014,12 +8336,16 @@ function nodeFailure(action) {
|
|
|
8014
8336
|
)
|
|
8015
8337
|
};
|
|
8016
8338
|
}
|
|
8017
|
-
var 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;
|
|
8339
|
+
var 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;
|
|
8018
8340
|
var init_exploration = __esm({
|
|
8019
8341
|
"src/operations/exploration.ts"() {
|
|
8020
8342
|
"use strict";
|
|
8021
8343
|
init_errors();
|
|
8022
8344
|
init_secrets();
|
|
8345
|
+
MAX_KV_VALUE_BYTES = 1024 * 1024;
|
|
8346
|
+
DEFAULT_KV_LIST_LIMIT = 100;
|
|
8347
|
+
MAX_ACCOUNT_REGISTRY_RECORDS = 1e3;
|
|
8348
|
+
MAX_ACCOUNT_REGISTRY_BYTES = 4 * 1024 * 1024;
|
|
8023
8349
|
EmptyInputSchema2 = z4.object({}).strict();
|
|
8024
8350
|
SpaceSchema = z4.string().min(1).refine(
|
|
8025
8351
|
(space) => (/^[A-Za-z0-9_-]+$/.test(space) || space.startsWith("tinycloud:")) && !space.includes("*"),
|
|
@@ -8033,6 +8359,33 @@ var init_exploration = __esm({
|
|
|
8033
8359
|
(key) => key !== "/" && !key.endsWith("/") && !key.includes("*"),
|
|
8034
8360
|
"Invalid KV key."
|
|
8035
8361
|
);
|
|
8362
|
+
LimitSchema = z4.number().int().min(1).max(1e3);
|
|
8363
|
+
StrongEtagSchema = z4.string().regex(
|
|
8364
|
+
/^"blake3-[0-9a-f]{64}"$/,
|
|
8365
|
+
"A strong TinyCloud BLAKE3 ETag is required."
|
|
8366
|
+
);
|
|
8367
|
+
ContentTypeSchema = z4.string().min(1).max(128).refine(
|
|
8368
|
+
(value) => !/[\x00-\x1f\x7f]/.test(value),
|
|
8369
|
+
"Invalid content type."
|
|
8370
|
+
);
|
|
8371
|
+
JsonNumberSchema = z4.number().finite().refine(
|
|
8372
|
+
(value) => !Number.isInteger(value) || Number.isSafeInteger(value),
|
|
8373
|
+
"JSON integer values must be JavaScript safe integers."
|
|
8374
|
+
);
|
|
8375
|
+
JsonValueSchema = z4.lazy(() => z4.union([
|
|
8376
|
+
z4.null(),
|
|
8377
|
+
z4.boolean(),
|
|
8378
|
+
JsonNumberSchema,
|
|
8379
|
+
z4.string(),
|
|
8380
|
+
z4.array(JsonValueSchema),
|
|
8381
|
+
z4.record(JsonValueSchema)
|
|
8382
|
+
]));
|
|
8383
|
+
KvMetadataSchema = z4.object({
|
|
8384
|
+
etag: z4.string().optional(),
|
|
8385
|
+
contentType: z4.string().optional(),
|
|
8386
|
+
lastModified: z4.string().optional(),
|
|
8387
|
+
contentLength: z4.number().int().nonnegative().optional()
|
|
8388
|
+
}).strict();
|
|
8036
8389
|
AccountSpaceSchema = z4.object({
|
|
8037
8390
|
spaceId: z4.string().min(1),
|
|
8038
8391
|
name: z4.string().min(1),
|
|
@@ -8062,17 +8415,20 @@ var init_exploration = __esm({
|
|
|
8062
8415
|
}).strict();
|
|
8063
8416
|
KvListInputSchema = z4.object({
|
|
8064
8417
|
space: SpaceSchema,
|
|
8065
|
-
prefix: PrefixSchema.optional()
|
|
8418
|
+
prefix: PrefixSchema.optional(),
|
|
8419
|
+
limit: LimitSchema.optional()
|
|
8066
8420
|
}).strict();
|
|
8067
8421
|
KvListOutputSchema = z4.object({
|
|
8068
8422
|
space: z4.string().min(1),
|
|
8069
8423
|
prefix: z4.string(),
|
|
8070
8424
|
keys: z4.array(z4.string()),
|
|
8071
|
-
count: z4.number().int().nonnegative()
|
|
8425
|
+
count: z4.number().int().nonnegative(),
|
|
8426
|
+
truncated: z4.boolean()
|
|
8072
8427
|
}).strict();
|
|
8073
8428
|
KvGetInputSchema = z4.object({
|
|
8074
8429
|
space: SpaceSchema,
|
|
8075
|
-
key: KeySchema
|
|
8430
|
+
key: KeySchema,
|
|
8431
|
+
representation: z4.enum(["base64", "text", "json"]).optional()
|
|
8076
8432
|
}).strict();
|
|
8077
8433
|
KvGetOutputSchema = z4.object({
|
|
8078
8434
|
space: z4.string().min(1),
|
|
@@ -8086,12 +8442,61 @@ var init_exploration = __esm({
|
|
|
8086
8442
|
z4.record(z4.unknown())
|
|
8087
8443
|
]),
|
|
8088
8444
|
encoding: z4.enum(["json", "text", "base64"]),
|
|
8089
|
-
metadata:
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
}).strict()
|
|
8445
|
+
metadata: KvMetadataSchema,
|
|
8446
|
+
byteLength: z4.number().int().nonnegative()
|
|
8447
|
+
}).strict();
|
|
8448
|
+
KvPutContentSchema = z4.discriminatedUnion("encoding", [
|
|
8449
|
+
z4.object({ encoding: z4.literal("utf8"), value: z4.string() }).strict(),
|
|
8450
|
+
z4.object({ encoding: z4.literal("json"), value: JsonValueSchema }).strict(),
|
|
8451
|
+
z4.object({ encoding: z4.literal("base64"), value: z4.string() }).strict()
|
|
8452
|
+
]).superRefine((content, context) => {
|
|
8453
|
+
const decoded = decodeKvPutContent(content);
|
|
8454
|
+
if (decoded === void 0) {
|
|
8455
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, message: "Invalid canonical base64 content." });
|
|
8456
|
+
} else if (decoded.byteLength > MAX_KV_VALUE_BYTES) {
|
|
8457
|
+
context.addIssue({
|
|
8458
|
+
code: z4.ZodIssueCode.too_big,
|
|
8459
|
+
type: "array",
|
|
8460
|
+
maximum: MAX_KV_VALUE_BYTES,
|
|
8461
|
+
inclusive: true,
|
|
8462
|
+
message: `KV content must not exceed ${MAX_KV_VALUE_BYTES} bytes.`
|
|
8463
|
+
});
|
|
8464
|
+
}
|
|
8465
|
+
});
|
|
8466
|
+
KvPutCommonSchema = {
|
|
8467
|
+
space: SpaceSchema,
|
|
8468
|
+
key: KeySchema,
|
|
8469
|
+
content: KvPutContentSchema,
|
|
8470
|
+
contentType: ContentTypeSchema.optional()
|
|
8471
|
+
};
|
|
8472
|
+
KvPutInputSchema = z4.discriminatedUnion("mode", [
|
|
8473
|
+
z4.object({ ...KvPutCommonSchema, mode: z4.literal("create") }).strict(),
|
|
8474
|
+
z4.object({ ...KvPutCommonSchema, mode: z4.literal("upsert") }).strict(),
|
|
8475
|
+
z4.object({ ...KvPutCommonSchema, mode: z4.literal("replace"), etag: StrongEtagSchema }).strict()
|
|
8476
|
+
]);
|
|
8477
|
+
KvPutOutputSchema = z4.object({
|
|
8478
|
+
space: z4.string().min(1),
|
|
8479
|
+
key: z4.string().min(1),
|
|
8480
|
+
mode: z4.enum(["create", "replace", "upsert"]),
|
|
8481
|
+
byteLength: z4.number().int().nonnegative(),
|
|
8482
|
+
metadata: KvMetadataSchema
|
|
8483
|
+
}).strict();
|
|
8484
|
+
KvHeadInputSchema = z4.object({ space: SpaceSchema, key: KeySchema }).strict();
|
|
8485
|
+
KvHeadOutputSchema = z4.object({
|
|
8486
|
+
space: z4.string().min(1),
|
|
8487
|
+
key: z4.string().min(1),
|
|
8488
|
+
metadata: KvMetadataSchema
|
|
8489
|
+
}).strict();
|
|
8490
|
+
KvDeleteInputSchema = z4.object({
|
|
8491
|
+
space: SpaceSchema,
|
|
8492
|
+
key: KeySchema,
|
|
8493
|
+
etag: StrongEtagSchema.optional()
|
|
8494
|
+
}).strict();
|
|
8495
|
+
KvDeleteOutputSchema = z4.object({
|
|
8496
|
+
space: z4.string().min(1),
|
|
8497
|
+
key: z4.string().min(1),
|
|
8498
|
+
deleted: z4.literal(true),
|
|
8499
|
+
etag: z4.string().optional()
|
|
8095
8500
|
}).strict();
|
|
8096
8501
|
AUTHENTICATED_POSTURES = [
|
|
8097
8502
|
"owner-openkey",
|
|
@@ -8123,6 +8528,8 @@ var init_exploration = __esm({
|
|
|
8123
8528
|
input: ["/key"],
|
|
8124
8529
|
output: ["/value"]
|
|
8125
8530
|
};
|
|
8531
|
+
KV_PUT_SENSITIVITY = { input: ["/key", "/content"], output: [] };
|
|
8532
|
+
KV_KEY_SENSITIVITY = { input: ["/key"], output: [] };
|
|
8126
8533
|
explorationOperationDefinitions = [
|
|
8127
8534
|
{
|
|
8128
8535
|
id: "tinycloud.account.spaces.list",
|
|
@@ -8173,7 +8580,7 @@ var init_exploration = __esm({
|
|
|
8173
8580
|
id: "tinycloud.kv.get",
|
|
8174
8581
|
version: 1,
|
|
8175
8582
|
title: "Get a TinyCloud KV value",
|
|
8176
|
-
description: "Read one exact key
|
|
8583
|
+
description: "Read one exact key with a node-enforced one MiB response limit.",
|
|
8177
8584
|
input: KvGetInputSchema,
|
|
8178
8585
|
output: KvGetOutputSchema,
|
|
8179
8586
|
effects: ["read"],
|
|
@@ -8183,6 +8590,51 @@ var init_exploration = __esm({
|
|
|
8183
8590
|
sensitivity: KV_GET_SENSITIVITY,
|
|
8184
8591
|
authority: planKvGet,
|
|
8185
8592
|
execute: executeKvGet
|
|
8593
|
+
},
|
|
8594
|
+
{
|
|
8595
|
+
id: "tinycloud.kv.head",
|
|
8596
|
+
version: 1,
|
|
8597
|
+
title: "Inspect TinyCloud KV metadata",
|
|
8598
|
+
description: "Read metadata for one exact key without downloading its value.",
|
|
8599
|
+
input: KvHeadInputSchema,
|
|
8600
|
+
output: KvHeadOutputSchema,
|
|
8601
|
+
effects: ["read"],
|
|
8602
|
+
runtime: "authenticated",
|
|
8603
|
+
postures: AUTHENTICATED_POSTURES,
|
|
8604
|
+
exposure: EXPLORATION_EXPOSURE,
|
|
8605
|
+
sensitivity: KV_KEY_SENSITIVITY,
|
|
8606
|
+
authority: (context, input) => planExactKv(context, input.space, input.key, "tinycloud.kv/metadata"),
|
|
8607
|
+
execute: executeKvHead
|
|
8608
|
+
},
|
|
8609
|
+
{
|
|
8610
|
+
id: "tinycloud.kv.put",
|
|
8611
|
+
version: 1,
|
|
8612
|
+
title: "Write a TinyCloud KV value",
|
|
8613
|
+
description: "Create, conditionally replace, or explicitly upsert one exact KV key.",
|
|
8614
|
+
input: KvPutInputSchema,
|
|
8615
|
+
output: KvPutOutputSchema,
|
|
8616
|
+
effects: ["write"],
|
|
8617
|
+
runtime: "authenticated",
|
|
8618
|
+
postures: AUTHENTICATED_POSTURES,
|
|
8619
|
+
exposure: EXPLORATION_EXPOSURE,
|
|
8620
|
+
sensitivity: KV_PUT_SENSITIVITY,
|
|
8621
|
+
authority: (context, input) => planExactKv(context, input.space, input.key, "tinycloud.kv/put"),
|
|
8622
|
+
execute: executeKvPut
|
|
8623
|
+
},
|
|
8624
|
+
{
|
|
8625
|
+
id: "tinycloud.kv.delete",
|
|
8626
|
+
version: 1,
|
|
8627
|
+
title: "Delete a TinyCloud KV value",
|
|
8628
|
+
description: "Delete one exact KV key, optionally only when its ETag still matches.",
|
|
8629
|
+
input: KvDeleteInputSchema,
|
|
8630
|
+
output: KvDeleteOutputSchema,
|
|
8631
|
+
effects: ["destructive"],
|
|
8632
|
+
runtime: "authenticated",
|
|
8633
|
+
postures: AUTHENTICATED_POSTURES,
|
|
8634
|
+
exposure: EXPLORATION_EXPOSURE,
|
|
8635
|
+
sensitivity: KV_KEY_SENSITIVITY,
|
|
8636
|
+
authority: (context, input) => planExactKv(context, input.space, input.key, "tinycloud.kv/del"),
|
|
8637
|
+
execute: executeKvDelete
|
|
8186
8638
|
}
|
|
8187
8639
|
];
|
|
8188
8640
|
}
|
|
@@ -8397,8 +8849,543 @@ var init_secrets_get = __esm({
|
|
|
8397
8849
|
}
|
|
8398
8850
|
});
|
|
8399
8851
|
|
|
8400
|
-
// src/operations/
|
|
8852
|
+
// src/operations/sql.ts
|
|
8853
|
+
import nodeSqlParser from "node-sql-parser";
|
|
8401
8854
|
import { z as z6 } from "zod";
|
|
8855
|
+
async function planSqlRead(context, input) {
|
|
8856
|
+
const space = resolveSqlSpace(context, input.space);
|
|
8857
|
+
return [{
|
|
8858
|
+
service: "tinycloud.sql",
|
|
8859
|
+
space,
|
|
8860
|
+
path: input.database,
|
|
8861
|
+
actions: ["tinycloud.sql/read"]
|
|
8862
|
+
}];
|
|
8863
|
+
}
|
|
8864
|
+
async function planSqlWrite(context, input) {
|
|
8865
|
+
const space = resolveSqlSpace(context, input.space);
|
|
8866
|
+
return [{
|
|
8867
|
+
service: "tinycloud.sql",
|
|
8868
|
+
space,
|
|
8869
|
+
path: input.database,
|
|
8870
|
+
actions: ["tinycloud.sql/write"],
|
|
8871
|
+
description: SQL_WRITE_AUTHORITY_NOTICE
|
|
8872
|
+
}];
|
|
8873
|
+
}
|
|
8874
|
+
async function executeSqlSchemaInspect(context, input) {
|
|
8875
|
+
try {
|
|
8876
|
+
const runtime = runtimeContext2(context);
|
|
8877
|
+
const space = resolveSqlSpace(runtime, input.space);
|
|
8878
|
+
const result = await runtimeNode2(runtime).sqlForSpace(space).db(input.database).query(SCHEMA_QUERY, [], { maxRows: SCHEMA_MAX_ROWS, maxBytes: SCHEMA_MAX_BYTES });
|
|
8879
|
+
if (!result.ok) return sqlServiceFailure(result.error, "inspect the SQLite schema");
|
|
8880
|
+
const normalized = normalizeQueryResult(result.data, SCHEMA_MAX_ROWS, SCHEMA_MAX_BYTES);
|
|
8881
|
+
const objects = normalized.rows.map((row) => schemaObject(row));
|
|
8882
|
+
return {
|
|
8883
|
+
status: "ok",
|
|
8884
|
+
output: {
|
|
8885
|
+
space,
|
|
8886
|
+
database: input.database,
|
|
8887
|
+
objects,
|
|
8888
|
+
count: objects.length,
|
|
8889
|
+
limits: limitsOutput(SCHEMA_MAX_ROWS, SCHEMA_MAX_BYTES)
|
|
8890
|
+
}
|
|
8891
|
+
};
|
|
8892
|
+
} catch (error) {
|
|
8893
|
+
return sqlFailure(error, "inspect the SQLite schema");
|
|
8894
|
+
}
|
|
8895
|
+
}
|
|
8896
|
+
async function executeSqlQuery(context, input) {
|
|
8897
|
+
try {
|
|
8898
|
+
if (!isSingleReadQuery(input.sql)) {
|
|
8899
|
+
return {
|
|
8900
|
+
status: "error",
|
|
8901
|
+
error: operationError(
|
|
8902
|
+
"SQL_QUERY_INVALID",
|
|
8903
|
+
"SQL must parse as exactly one SQLite SELECT statement."
|
|
8904
|
+
)
|
|
8905
|
+
};
|
|
8906
|
+
}
|
|
8907
|
+
const runtime = runtimeContext2(context);
|
|
8908
|
+
const space = resolveSqlSpace(runtime, input.space);
|
|
8909
|
+
const maxRows = input.maxRows ?? DEFAULT_MAX_ROWS;
|
|
8910
|
+
const maxBytes = input.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
8911
|
+
const params = (input.params ?? []).map(decodeSqlInputValue);
|
|
8912
|
+
const result = await runtimeNode2(runtime).sqlForSpace(space).db(input.database).query(input.sql, params, { maxRows, maxBytes });
|
|
8913
|
+
if (!result.ok) return sqlServiceFailure(result.error, "run the SQLite query");
|
|
8914
|
+
const normalized = normalizeQueryResult(result.data, maxRows, maxBytes);
|
|
8915
|
+
return {
|
|
8916
|
+
status: "ok",
|
|
8917
|
+
output: {
|
|
8918
|
+
space,
|
|
8919
|
+
database: input.database,
|
|
8920
|
+
columns: normalized.columns,
|
|
8921
|
+
rows: normalized.rows,
|
|
8922
|
+
rowCount: normalized.rows.length,
|
|
8923
|
+
limits: limitsOutput(maxRows, maxBytes)
|
|
8924
|
+
}
|
|
8925
|
+
};
|
|
8926
|
+
} catch (error) {
|
|
8927
|
+
return sqlFailure(error, "run the SQLite query");
|
|
8928
|
+
}
|
|
8929
|
+
}
|
|
8930
|
+
async function executeSqlDml(context, input) {
|
|
8931
|
+
try {
|
|
8932
|
+
const statementType = parseSingleDmlStatement(input.sql, input.params.length);
|
|
8933
|
+
if (statementType === void 0) {
|
|
8934
|
+
return {
|
|
8935
|
+
status: "error",
|
|
8936
|
+
error: operationError(
|
|
8937
|
+
"SQL_QUERY_INVALID",
|
|
8938
|
+
"SQL must parse as exactly one parameterized INSERT, UPDATE, or DELETE with one value per positional placeholder."
|
|
8939
|
+
)
|
|
8940
|
+
};
|
|
8941
|
+
}
|
|
8942
|
+
const runtime = runtimeContext2(context);
|
|
8943
|
+
const space = resolveSqlSpace(runtime, input.space);
|
|
8944
|
+
const result = await runtimeNode2(runtime).sqlForSpace(space).db(input.database).execute(input.sql, input.params.map(decodeSqlInputValue));
|
|
8945
|
+
if (!result.ok) return sqlMutationFailure();
|
|
8946
|
+
const normalized = normalizeExecuteResult(result.data);
|
|
8947
|
+
return {
|
|
8948
|
+
status: "ok",
|
|
8949
|
+
output: {
|
|
8950
|
+
space,
|
|
8951
|
+
database: input.database,
|
|
8952
|
+
statementType,
|
|
8953
|
+
...normalized,
|
|
8954
|
+
authorityNotice: SQL_WRITE_AUTHORITY_NOTICE
|
|
8955
|
+
}
|
|
8956
|
+
};
|
|
8957
|
+
} catch (error) {
|
|
8958
|
+
return sqlFailure(error, "execute the SQLite statement");
|
|
8959
|
+
}
|
|
8960
|
+
}
|
|
8961
|
+
function isSingleReadQuery(sql) {
|
|
8962
|
+
const ast = parseSingleStatement(sql);
|
|
8963
|
+
return ast !== void 0 && ast.type === "select";
|
|
8964
|
+
}
|
|
8965
|
+
function parseSingleDmlStatement(sql, parameterCount) {
|
|
8966
|
+
const ast = parseSingleStatement(sql);
|
|
8967
|
+
if (ast === void 0 || ast.type !== "insert" && ast.type !== "update" && ast.type !== "delete" || ast.with !== void 0 && ast.with !== null) {
|
|
8968
|
+
return void 0;
|
|
8969
|
+
}
|
|
8970
|
+
const placeholders = countPositionalParameters(ast);
|
|
8971
|
+
return placeholders > 0 && placeholders === parameterCount ? ast.type : void 0;
|
|
8972
|
+
}
|
|
8973
|
+
function parseSingleStatement(sql) {
|
|
8974
|
+
try {
|
|
8975
|
+
const ast = sqlParser.astify(sql, { database: "sqlite" });
|
|
8976
|
+
return !Array.isArray(ast) && isRecord3(ast) ? ast : void 0;
|
|
8977
|
+
} catch {
|
|
8978
|
+
return void 0;
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
function countPositionalParameters(value) {
|
|
8982
|
+
if (Array.isArray(value)) {
|
|
8983
|
+
return value.reduce((count, entry) => count + countPositionalParameters(entry), 0);
|
|
8984
|
+
}
|
|
8985
|
+
if (!isRecord3(value)) return 0;
|
|
8986
|
+
const current = value.type === "origin" && value.value === "?" ? 1 : 0;
|
|
8987
|
+
return Object.values(value).reduce(
|
|
8988
|
+
(count, entry) => count + countPositionalParameters(entry),
|
|
8989
|
+
current
|
|
8990
|
+
);
|
|
8991
|
+
}
|
|
8992
|
+
function decodeSqlInputValue(value) {
|
|
8993
|
+
if (isRecord3(value) && value.type === "blob") {
|
|
8994
|
+
return new Uint8Array(Buffer.from(value.base64, "base64"));
|
|
8995
|
+
}
|
|
8996
|
+
return value;
|
|
8997
|
+
}
|
|
8998
|
+
function normalizeQueryResult(value, maxRows, maxBytes) {
|
|
8999
|
+
if (!isRecord3(value) || !Array.isArray(value.columns) || !Array.isArray(value.rows)) {
|
|
9000
|
+
throw unsafeSqlValue("The node returned an invalid SQLite query result.");
|
|
9001
|
+
}
|
|
9002
|
+
const columns = value.columns.map((column) => {
|
|
9003
|
+
if (typeof column !== "string") {
|
|
9004
|
+
throw unsafeSqlValue("The node returned an invalid SQLite column name.");
|
|
9005
|
+
}
|
|
9006
|
+
return column;
|
|
9007
|
+
});
|
|
9008
|
+
const rows = value.rows.map((row) => {
|
|
9009
|
+
if (!Array.isArray(row) || row.length !== columns.length) {
|
|
9010
|
+
throw unsafeSqlValue("The node returned an invalid SQLite row.");
|
|
9011
|
+
}
|
|
9012
|
+
return row.map(normalizeSqlOutputValue);
|
|
9013
|
+
});
|
|
9014
|
+
const serializedBytes = Buffer.byteLength(JSON.stringify({ columns, rows }), "utf8");
|
|
9015
|
+
if (rows.length > maxRows || serializedBytes > maxBytes) {
|
|
9016
|
+
throw new OperationInvocationError(operationError(
|
|
9017
|
+
"SQL_RESULT_LIMIT_EXCEEDED",
|
|
9018
|
+
"The SQLite query result exceeded the requested result limits.",
|
|
9019
|
+
{
|
|
9020
|
+
details: {
|
|
9021
|
+
maxRows,
|
|
9022
|
+
maxBytes,
|
|
9023
|
+
returnedRows: rows.length,
|
|
9024
|
+
returnedBytes: serializedBytes
|
|
9025
|
+
}
|
|
9026
|
+
}
|
|
9027
|
+
));
|
|
9028
|
+
}
|
|
9029
|
+
return { columns, rows };
|
|
9030
|
+
}
|
|
9031
|
+
function normalizeSqlOutputValue(value) {
|
|
9032
|
+
if (value === null || typeof value === "string") return value;
|
|
9033
|
+
if (typeof value === "number") {
|
|
9034
|
+
if (!Number.isFinite(value) || Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
9035
|
+
throw unsafeSqlValue("The node returned an integer that cannot be represented safely in JavaScript.");
|
|
9036
|
+
}
|
|
9037
|
+
return value;
|
|
9038
|
+
}
|
|
9039
|
+
if (value instanceof Uint8Array) return encodeBlob(value);
|
|
9040
|
+
if (Array.isArray(value) && value.every(isByte)) {
|
|
9041
|
+
return encodeBlob(Uint8Array.from(value));
|
|
9042
|
+
}
|
|
9043
|
+
if (isRecord3(value) && value.type === "Buffer" && Array.isArray(value.data) && value.data.every(isByte)) {
|
|
9044
|
+
return encodeBlob(Uint8Array.from(value.data));
|
|
9045
|
+
}
|
|
9046
|
+
throw unsafeSqlValue("The node returned an unsupported SQLite value.");
|
|
9047
|
+
}
|
|
9048
|
+
function normalizeExecuteResult(value) {
|
|
9049
|
+
if (!isRecord3(value) || !Number.isSafeInteger(value.changes) || value.changes < 0 || value.lastInsertRowId !== null && !Number.isSafeInteger(value.lastInsertRowId)) {
|
|
9050
|
+
throw unsafeSqlValue("The node returned SQLite mutation metadata that cannot be represented safely in JavaScript.");
|
|
9051
|
+
}
|
|
9052
|
+
return {
|
|
9053
|
+
changes: value.changes,
|
|
9054
|
+
lastInsertRowId: value.lastInsertRowId
|
|
9055
|
+
};
|
|
9056
|
+
}
|
|
9057
|
+
function schemaObject(row) {
|
|
9058
|
+
const [type, name, tableName, sql] = row;
|
|
9059
|
+
if (type !== "table" && type !== "view" && type !== "index" && type !== "trigger" || typeof name !== "string" || typeof tableName !== "string" || sql !== null && typeof sql !== "string") {
|
|
9060
|
+
throw unsafeSqlValue("The node returned an invalid SQLite schema record.");
|
|
9061
|
+
}
|
|
9062
|
+
return {
|
|
9063
|
+
type,
|
|
9064
|
+
name,
|
|
9065
|
+
tableName,
|
|
9066
|
+
...sql === null ? {} : { sql }
|
|
9067
|
+
};
|
|
9068
|
+
}
|
|
9069
|
+
function limitsOutput(maxRows, maxBytes) {
|
|
9070
|
+
return { maxRows, maxBytes, enforcement: "node-requested-client-verified" };
|
|
9071
|
+
}
|
|
9072
|
+
function runtimeContext2(context) {
|
|
9073
|
+
if (context.runtime === void 0) {
|
|
9074
|
+
throw new TypeError("Authenticated operation runtime is unavailable.");
|
|
9075
|
+
}
|
|
9076
|
+
return context;
|
|
9077
|
+
}
|
|
9078
|
+
function runtimeNode2(context) {
|
|
9079
|
+
return context.runtime.node;
|
|
9080
|
+
}
|
|
9081
|
+
function resolveSqlSpace(context, space) {
|
|
9082
|
+
const resolved = operationSpaceResolver(
|
|
9083
|
+
context.runtime.node,
|
|
9084
|
+
context.summary.space
|
|
9085
|
+
)(space);
|
|
9086
|
+
const name = resolved.split(":").at(-1)?.toLowerCase();
|
|
9087
|
+
if (name === "secrets" || name === "account") {
|
|
9088
|
+
throw new OperationInvocationError(operationError(
|
|
9089
|
+
"INPUT_INVALID",
|
|
9090
|
+
"Generic SQL operations cannot access protected TinyCloud account or secrets spaces."
|
|
9091
|
+
));
|
|
9092
|
+
}
|
|
9093
|
+
return resolved;
|
|
9094
|
+
}
|
|
9095
|
+
function encodeBlob(value) {
|
|
9096
|
+
return {
|
|
9097
|
+
type: "blob",
|
|
9098
|
+
base64: Buffer.from(value).toString("base64"),
|
|
9099
|
+
byteLength: value.byteLength
|
|
9100
|
+
};
|
|
9101
|
+
}
|
|
9102
|
+
function unsafeSqlValue(message) {
|
|
9103
|
+
return new OperationInvocationError(operationError("SQL_VALUE_UNSAFE", message));
|
|
9104
|
+
}
|
|
9105
|
+
function sqlFailure(error, action) {
|
|
9106
|
+
if (error instanceof OperationInvocationError) {
|
|
9107
|
+
return { status: "error", error: error.operationError };
|
|
9108
|
+
}
|
|
9109
|
+
return nodeFailure2(action);
|
|
9110
|
+
}
|
|
9111
|
+
function nodeFailure2(action) {
|
|
9112
|
+
return {
|
|
9113
|
+
status: "error",
|
|
9114
|
+
error: operationError(
|
|
9115
|
+
"NODE_ERROR",
|
|
9116
|
+
`The TinyCloud node could not ${action}.`,
|
|
9117
|
+
{ retryable: true }
|
|
9118
|
+
)
|
|
9119
|
+
};
|
|
9120
|
+
}
|
|
9121
|
+
function sqlServiceFailure(error, action) {
|
|
9122
|
+
if (isRecord3(error) && error.code === "SQL_RESPONSE_TOO_LARGE") {
|
|
9123
|
+
return {
|
|
9124
|
+
status: "error",
|
|
9125
|
+
error: operationError(
|
|
9126
|
+
"SQL_RESULT_LIMIT_EXCEEDED",
|
|
9127
|
+
"The SQLite query result exceeded the requested result limits."
|
|
9128
|
+
)
|
|
9129
|
+
};
|
|
9130
|
+
}
|
|
9131
|
+
return nodeFailure2(action);
|
|
9132
|
+
}
|
|
9133
|
+
function sqlMutationFailure() {
|
|
9134
|
+
return {
|
|
9135
|
+
status: "error",
|
|
9136
|
+
error: operationError(
|
|
9137
|
+
"SQL_EXECUTION_FAILED",
|
|
9138
|
+
"The SQLite statement outcome is unknown; inspect database state before considering another write.",
|
|
9139
|
+
{ retryable: false }
|
|
9140
|
+
)
|
|
9141
|
+
};
|
|
9142
|
+
}
|
|
9143
|
+
function isCanonicalBase642(value) {
|
|
9144
|
+
if (value === "") return true;
|
|
9145
|
+
if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) return false;
|
|
9146
|
+
return Buffer.from(value, "base64").toString("base64") === value;
|
|
9147
|
+
}
|
|
9148
|
+
function sqlInputValueBytes(value) {
|
|
9149
|
+
if (typeof value === "string") return Buffer.byteLength(value, "utf8");
|
|
9150
|
+
if (isRecord3(value) && value.type === "blob") {
|
|
9151
|
+
return Buffer.from(value.base64, "base64").byteLength;
|
|
9152
|
+
}
|
|
9153
|
+
return 8;
|
|
9154
|
+
}
|
|
9155
|
+
function isByte(value) {
|
|
9156
|
+
return Number.isInteger(value) && value >= 0 && value <= 255;
|
|
9157
|
+
}
|
|
9158
|
+
function isRecord3(value) {
|
|
9159
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9160
|
+
}
|
|
9161
|
+
var 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;
|
|
9162
|
+
var init_sql = __esm({
|
|
9163
|
+
"src/operations/sql.ts"() {
|
|
9164
|
+
"use strict";
|
|
9165
|
+
init_errors();
|
|
9166
|
+
init_secrets();
|
|
9167
|
+
DEFAULT_MAX_ROWS = 100;
|
|
9168
|
+
MAX_MAX_ROWS = 1e3;
|
|
9169
|
+
DEFAULT_MAX_BYTES = 1024 * 1024;
|
|
9170
|
+
MAX_MAX_BYTES = 4 * 1024 * 1024;
|
|
9171
|
+
SCHEMA_MAX_ROWS = 500;
|
|
9172
|
+
SCHEMA_MAX_BYTES = 1024 * 1024;
|
|
9173
|
+
MAX_PARAMETERS = 100;
|
|
9174
|
+
MAX_SQL_LENGTH = 64 * 1024;
|
|
9175
|
+
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.";
|
|
9176
|
+
SCHEMA_QUERY = `SELECT type, name, tbl_name, sql
|
|
9177
|
+
FROM sqlite_schema
|
|
9178
|
+
WHERE type IN ('table', 'view', 'index', 'trigger')
|
|
9179
|
+
AND name NOT LIKE 'sqlite_%'
|
|
9180
|
+
ORDER BY type, name`;
|
|
9181
|
+
sqlParser = new nodeSqlParser.Parser();
|
|
9182
|
+
SpaceSchema2 = z6.string().min(1).refine(
|
|
9183
|
+
(space) => (/^[A-Za-z0-9_-]+$/.test(space) || space.startsWith("tinycloud:")) && !space.includes("*"),
|
|
9184
|
+
"Invalid TinyCloud space."
|
|
9185
|
+
);
|
|
9186
|
+
DatabaseSchema = z6.string().min(1).max(256).refine(
|
|
9187
|
+
(database) => database !== "/" && !database.endsWith("/") && !database.includes("*") && !/[\u0000-\u001f\u007f]/.test(database),
|
|
9188
|
+
"Invalid SQLite database name."
|
|
9189
|
+
);
|
|
9190
|
+
SafeNumberSchema = z6.number().finite().refine(
|
|
9191
|
+
(value) => !Number.isInteger(value) || Number.isSafeInteger(value),
|
|
9192
|
+
"SQLite integer parameters must be JavaScript safe integers."
|
|
9193
|
+
);
|
|
9194
|
+
Base64Schema = z6.string().max(Math.ceil(MAX_MAX_BYTES / 3) * 4).refine(
|
|
9195
|
+
isCanonicalBase642,
|
|
9196
|
+
"Invalid base64 BLOB value."
|
|
9197
|
+
);
|
|
9198
|
+
SqlInputValueSchema = z6.union([
|
|
9199
|
+
z6.null(),
|
|
9200
|
+
SafeNumberSchema,
|
|
9201
|
+
z6.string().max(MAX_MAX_BYTES),
|
|
9202
|
+
z6.object({ type: z6.literal("blob"), base64: Base64Schema }).strict()
|
|
9203
|
+
]);
|
|
9204
|
+
SqlParamsSchema = z6.array(SqlInputValueSchema).max(MAX_PARAMETERS).superRefine(
|
|
9205
|
+
(params, context) => {
|
|
9206
|
+
const totalBytes = params.reduce(
|
|
9207
|
+
(total, value) => total + sqlInputValueBytes(value),
|
|
9208
|
+
0
|
|
9209
|
+
);
|
|
9210
|
+
if (totalBytes > MAX_MAX_BYTES) {
|
|
9211
|
+
context.addIssue({
|
|
9212
|
+
code: z6.ZodIssueCode.custom,
|
|
9213
|
+
message: "SQLite query parameters exceed the 4 MiB input limit."
|
|
9214
|
+
});
|
|
9215
|
+
}
|
|
9216
|
+
}
|
|
9217
|
+
);
|
|
9218
|
+
RequiredSqlParamsSchema = z6.array(SqlInputValueSchema).min(1).max(MAX_PARAMETERS).superRefine(
|
|
9219
|
+
(params, context) => {
|
|
9220
|
+
const totalBytes = params.reduce(
|
|
9221
|
+
(total, value) => total + sqlInputValueBytes(value),
|
|
9222
|
+
0
|
|
9223
|
+
);
|
|
9224
|
+
if (totalBytes > MAX_MAX_BYTES) {
|
|
9225
|
+
context.addIssue({
|
|
9226
|
+
code: z6.ZodIssueCode.custom,
|
|
9227
|
+
message: "SQLite query parameters exceed the 4 MiB input limit."
|
|
9228
|
+
});
|
|
9229
|
+
}
|
|
9230
|
+
}
|
|
9231
|
+
);
|
|
9232
|
+
SqlOutputValueSchema = z6.union([
|
|
9233
|
+
z6.null(),
|
|
9234
|
+
SafeNumberSchema,
|
|
9235
|
+
z6.string(),
|
|
9236
|
+
z6.object({
|
|
9237
|
+
type: z6.literal("blob"),
|
|
9238
|
+
base64: z6.string(),
|
|
9239
|
+
byteLength: z6.number().int().nonnegative()
|
|
9240
|
+
}).strict()
|
|
9241
|
+
]);
|
|
9242
|
+
SqlTargetInputSchema = z6.object({
|
|
9243
|
+
space: SpaceSchema2,
|
|
9244
|
+
database: DatabaseSchema
|
|
9245
|
+
}).strict();
|
|
9246
|
+
SqlQueryInputSchema = z6.object({
|
|
9247
|
+
space: SpaceSchema2,
|
|
9248
|
+
database: DatabaseSchema,
|
|
9249
|
+
sql: z6.string().min(1).max(MAX_SQL_LENGTH).superRefine((sql, context) => {
|
|
9250
|
+
if (!isSingleReadQuery(sql)) {
|
|
9251
|
+
context.addIssue({
|
|
9252
|
+
code: z6.ZodIssueCode.custom,
|
|
9253
|
+
message: "SQL must parse as exactly one SQLite SELECT statement."
|
|
9254
|
+
});
|
|
9255
|
+
}
|
|
9256
|
+
}),
|
|
9257
|
+
params: SqlParamsSchema.optional(),
|
|
9258
|
+
maxRows: z6.number().int().positive().max(MAX_MAX_ROWS).optional(),
|
|
9259
|
+
maxBytes: z6.number().int().positive().max(MAX_MAX_BYTES).optional()
|
|
9260
|
+
}).strict();
|
|
9261
|
+
SqlExecuteInputSchema = z6.object({
|
|
9262
|
+
space: SpaceSchema2,
|
|
9263
|
+
database: DatabaseSchema,
|
|
9264
|
+
sql: z6.string().min(1).max(MAX_SQL_LENGTH),
|
|
9265
|
+
params: RequiredSqlParamsSchema,
|
|
9266
|
+
acknowledgeDatabaseWideAuthority: z6.literal(true).describe(SQL_WRITE_AUTHORITY_NOTICE)
|
|
9267
|
+
}).strict().superRefine((input, context) => {
|
|
9268
|
+
if (parseSingleDmlStatement(input.sql, input.params.length) === void 0) {
|
|
9269
|
+
context.addIssue({
|
|
9270
|
+
code: z6.ZodIssueCode.custom,
|
|
9271
|
+
path: ["sql"],
|
|
9272
|
+
message: "SQL must parse as exactly one parameterized INSERT, UPDATE, or DELETE with one value per positional placeholder."
|
|
9273
|
+
});
|
|
9274
|
+
}
|
|
9275
|
+
});
|
|
9276
|
+
SqlLimitsOutputSchema = z6.object({
|
|
9277
|
+
maxRows: z6.number().int().positive(),
|
|
9278
|
+
maxBytes: z6.number().int().positive(),
|
|
9279
|
+
enforcement: z6.literal("node-requested-client-verified")
|
|
9280
|
+
}).strict();
|
|
9281
|
+
SqlSchemaInspectOutputSchema = z6.object({
|
|
9282
|
+
space: z6.string().min(1),
|
|
9283
|
+
database: z6.string().min(1),
|
|
9284
|
+
objects: z6.array(z6.object({
|
|
9285
|
+
type: z6.enum(["table", "view", "index", "trigger"]),
|
|
9286
|
+
name: z6.string().min(1),
|
|
9287
|
+
tableName: z6.string().min(1),
|
|
9288
|
+
sql: z6.string().optional()
|
|
9289
|
+
}).strict()),
|
|
9290
|
+
count: z6.number().int().nonnegative(),
|
|
9291
|
+
limits: SqlLimitsOutputSchema
|
|
9292
|
+
}).strict();
|
|
9293
|
+
SqlQueryOutputSchema = z6.object({
|
|
9294
|
+
space: z6.string().min(1),
|
|
9295
|
+
database: z6.string().min(1),
|
|
9296
|
+
columns: z6.array(z6.string()),
|
|
9297
|
+
rows: z6.array(z6.array(SqlOutputValueSchema)),
|
|
9298
|
+
rowCount: z6.number().int().nonnegative(),
|
|
9299
|
+
limits: SqlLimitsOutputSchema
|
|
9300
|
+
}).strict();
|
|
9301
|
+
SqlExecuteOutputSchema = z6.object({
|
|
9302
|
+
space: z6.string().min(1),
|
|
9303
|
+
database: z6.string().min(1),
|
|
9304
|
+
statementType: z6.enum(["insert", "update", "delete"]),
|
|
9305
|
+
changes: z6.number().int().nonnegative(),
|
|
9306
|
+
lastInsertRowId: z6.number().int().nullable(),
|
|
9307
|
+
authorityNotice: z6.literal(SQL_WRITE_AUTHORITY_NOTICE)
|
|
9308
|
+
}).strict();
|
|
9309
|
+
AUTHENTICATED_POSTURES2 = [
|
|
9310
|
+
"owner-openkey",
|
|
9311
|
+
"delegate-session",
|
|
9312
|
+
"local-owner-key"
|
|
9313
|
+
];
|
|
9314
|
+
SQL_EXPOSURE = {
|
|
9315
|
+
cli: {
|
|
9316
|
+
status: "excluded",
|
|
9317
|
+
reason: "Existing SQL Commander commands remain the CLI surface."
|
|
9318
|
+
},
|
|
9319
|
+
mcp: { status: "required" },
|
|
9320
|
+
skill: { status: "required" },
|
|
9321
|
+
docs: { status: "required" }
|
|
9322
|
+
};
|
|
9323
|
+
SQL_SCHEMA_SENSITIVITY = {
|
|
9324
|
+
input: ["/database"],
|
|
9325
|
+
output: ["/objects"]
|
|
9326
|
+
};
|
|
9327
|
+
SQL_QUERY_SENSITIVITY = {
|
|
9328
|
+
input: ["/database", "/sql", "/params"],
|
|
9329
|
+
output: ["/columns", "/rows"]
|
|
9330
|
+
};
|
|
9331
|
+
SQL_EXECUTE_SENSITIVITY = {
|
|
9332
|
+
input: ["/database", "/sql", "/params"],
|
|
9333
|
+
output: ["/lastInsertRowId"]
|
|
9334
|
+
};
|
|
9335
|
+
sqlOperationDefinitions = [
|
|
9336
|
+
{
|
|
9337
|
+
id: "tinycloud.sql.schema.inspect",
|
|
9338
|
+
version: 1,
|
|
9339
|
+
title: "Inspect a TinyCloud SQLite schema",
|
|
9340
|
+
description: "List user tables, views, indexes, and triggers in one exact TinyCloud SQLite database using a fixed read-only query.",
|
|
9341
|
+
input: SqlTargetInputSchema,
|
|
9342
|
+
output: SqlSchemaInspectOutputSchema,
|
|
9343
|
+
effects: ["read"],
|
|
9344
|
+
runtime: "authenticated",
|
|
9345
|
+
postures: AUTHENTICATED_POSTURES2,
|
|
9346
|
+
exposure: SQL_EXPOSURE,
|
|
9347
|
+
sensitivity: SQL_SCHEMA_SENSITIVITY,
|
|
9348
|
+
authority: planSqlRead,
|
|
9349
|
+
execute: executeSqlSchemaInspect
|
|
9350
|
+
},
|
|
9351
|
+
{
|
|
9352
|
+
id: "tinycloud.sql.query",
|
|
9353
|
+
version: 1,
|
|
9354
|
+
title: "Query a TinyCloud SQLite database",
|
|
9355
|
+
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.",
|
|
9356
|
+
input: SqlQueryInputSchema,
|
|
9357
|
+
output: SqlQueryOutputSchema,
|
|
9358
|
+
effects: ["read"],
|
|
9359
|
+
runtime: "authenticated",
|
|
9360
|
+
postures: AUTHENTICATED_POSTURES2,
|
|
9361
|
+
exposure: SQL_EXPOSURE,
|
|
9362
|
+
sensitivity: SQL_QUERY_SENSITIVITY,
|
|
9363
|
+
invalidInputErrorCode: "SQL_QUERY_INVALID",
|
|
9364
|
+
authority: planSqlRead,
|
|
9365
|
+
execute: executeSqlQuery
|
|
9366
|
+
},
|
|
9367
|
+
{
|
|
9368
|
+
id: "tinycloud.sql.execute",
|
|
9369
|
+
version: 1,
|
|
9370
|
+
title: "Execute a TinyCloud SQLite DML statement",
|
|
9371
|
+
description: `Run exactly one parameterized INSERT, UPDATE, or DELETE against one exact TinyCloud SQLite database. ${SQL_WRITE_AUTHORITY_NOTICE}`,
|
|
9372
|
+
input: SqlExecuteInputSchema,
|
|
9373
|
+
output: SqlExecuteOutputSchema,
|
|
9374
|
+
effects: ["write", "destructive"],
|
|
9375
|
+
runtime: "authenticated",
|
|
9376
|
+
postures: AUTHENTICATED_POSTURES2,
|
|
9377
|
+
exposure: SQL_EXPOSURE,
|
|
9378
|
+
sensitivity: SQL_EXECUTE_SENSITIVITY,
|
|
9379
|
+
invalidInputErrorCode: "SQL_QUERY_INVALID",
|
|
9380
|
+
authority: planSqlWrite,
|
|
9381
|
+
execute: executeSqlDml
|
|
9382
|
+
}
|
|
9383
|
+
];
|
|
9384
|
+
}
|
|
9385
|
+
});
|
|
9386
|
+
|
|
9387
|
+
// src/operations/status.ts
|
|
9388
|
+
import { z as z7 } from "zod";
|
|
8402
9389
|
function createStatusDefinition(params) {
|
|
8403
9390
|
return {
|
|
8404
9391
|
id: params.id,
|
|
@@ -8453,7 +9440,7 @@ async function inspectPinnedProfileStatus(context, _input) {
|
|
|
8453
9440
|
async function pinnedProfileExists(profile) {
|
|
8454
9441
|
try {
|
|
8455
9442
|
const storedProfile = await readProfile(profile);
|
|
8456
|
-
return
|
|
9443
|
+
return isRecord4(storedProfile);
|
|
8457
9444
|
} catch {
|
|
8458
9445
|
return false;
|
|
8459
9446
|
}
|
|
@@ -8473,7 +9460,7 @@ async function countLiveAdditionalDelegations(profile) {
|
|
|
8473
9460
|
}
|
|
8474
9461
|
function summarizeSession(session) {
|
|
8475
9462
|
if (session === null) return { present: false, expired: null, expiresAt: null };
|
|
8476
|
-
if (!
|
|
9463
|
+
if (!isRecord4(session)) throw new TypeError("Invalid session store.");
|
|
8477
9464
|
const expiry = extractSessionExpiry(session);
|
|
8478
9465
|
if (expiry === null) return { present: true, expired: null, expiresAt: null };
|
|
8479
9466
|
return {
|
|
@@ -8483,7 +9470,7 @@ function summarizeSession(session) {
|
|
|
8483
9470
|
};
|
|
8484
9471
|
}
|
|
8485
9472
|
function storedDelegationExpiry(entry) {
|
|
8486
|
-
if (!
|
|
9473
|
+
if (!isRecord4(entry) || !isRecord4(entry.delegation) || !("expiry" in entry.delegation)) {
|
|
8487
9474
|
throw new TypeError("Invalid stored delegation.");
|
|
8488
9475
|
}
|
|
8489
9476
|
return parseExpiry(entry.delegation.expiry);
|
|
@@ -8512,7 +9499,7 @@ function profileNotFound(profile) {
|
|
|
8512
9499
|
)
|
|
8513
9500
|
};
|
|
8514
9501
|
}
|
|
8515
|
-
function
|
|
9502
|
+
function isRecord4(value) {
|
|
8516
9503
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8517
9504
|
}
|
|
8518
9505
|
var StatusInputSchema, StatusOutputSchema, STATUS_POSTURES, STATUS_EXPOSURE, STATUS_SENSITIVITY, statusOperationDefinitions;
|
|
@@ -8521,27 +9508,27 @@ var init_status = __esm({
|
|
|
8521
9508
|
"use strict";
|
|
8522
9509
|
init_errors();
|
|
8523
9510
|
init_state();
|
|
8524
|
-
StatusInputSchema =
|
|
8525
|
-
StatusOutputSchema =
|
|
8526
|
-
profile:
|
|
8527
|
-
host:
|
|
8528
|
-
posture:
|
|
9511
|
+
StatusInputSchema = z7.object({}).strict();
|
|
9512
|
+
StatusOutputSchema = z7.object({
|
|
9513
|
+
profile: z7.string().min(1),
|
|
9514
|
+
host: z7.string().min(1),
|
|
9515
|
+
posture: z7.enum([
|
|
8529
9516
|
"owner-openkey",
|
|
8530
9517
|
"delegate-session",
|
|
8531
9518
|
"local-owner-key",
|
|
8532
9519
|
"unauthenticated"
|
|
8533
9520
|
]),
|
|
8534
|
-
operatorType:
|
|
8535
|
-
principalDid:
|
|
8536
|
-
sessionDid:
|
|
8537
|
-
ownerDid:
|
|
8538
|
-
space:
|
|
8539
|
-
session:
|
|
8540
|
-
present:
|
|
8541
|
-
expired:
|
|
8542
|
-
expiresAt:
|
|
9521
|
+
operatorType: z7.enum(["human", "agent"]).optional(),
|
|
9522
|
+
principalDid: z7.string().min(1).optional(),
|
|
9523
|
+
sessionDid: z7.string().min(1).optional(),
|
|
9524
|
+
ownerDid: z7.string().min(1).optional(),
|
|
9525
|
+
space: z7.string().min(1).optional(),
|
|
9526
|
+
session: z7.object({
|
|
9527
|
+
present: z7.boolean(),
|
|
9528
|
+
expired: z7.boolean().nullable(),
|
|
9529
|
+
expiresAt: z7.string().datetime({ offset: true }).nullable()
|
|
8543
9530
|
}).strict(),
|
|
8544
|
-
liveAdditionalDelegationCount:
|
|
9531
|
+
liveAdditionalDelegationCount: z7.number().int().nonnegative()
|
|
8545
9532
|
}).strict();
|
|
8546
9533
|
STATUS_POSTURES = [
|
|
8547
9534
|
"owner-openkey",
|
|
@@ -8582,6 +9569,7 @@ function registeredOperationDefinitions() {
|
|
|
8582
9569
|
...statusOperationDefinitions,
|
|
8583
9570
|
...authOperationDefinitions,
|
|
8584
9571
|
...explorationOperationDefinitions,
|
|
9572
|
+
...sqlOperationDefinitions,
|
|
8585
9573
|
...secretsGetOperationDefinitions
|
|
8586
9574
|
]);
|
|
8587
9575
|
return operationDefinitions;
|
|
@@ -8614,6 +9602,7 @@ var init_registry = __esm({
|
|
|
8614
9602
|
init_auth();
|
|
8615
9603
|
init_exploration();
|
|
8616
9604
|
init_secrets_get();
|
|
9605
|
+
init_sql();
|
|
8617
9606
|
init_status();
|
|
8618
9607
|
}
|
|
8619
9608
|
});
|
|
@@ -8693,9 +9682,9 @@ function isOperatorType(value) {
|
|
|
8693
9682
|
return value === "human" || value === "agent";
|
|
8694
9683
|
}
|
|
8695
9684
|
function isStoredProfile(value) {
|
|
8696
|
-
return
|
|
9685
|
+
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);
|
|
8697
9686
|
}
|
|
8698
|
-
function
|
|
9687
|
+
function isRecord5(value) {
|
|
8699
9688
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8700
9689
|
}
|
|
8701
9690
|
function isNonEmptyString(value) {
|
|
@@ -8860,7 +9849,7 @@ function spaceForAuthenticatedPrincipal(principal2) {
|
|
|
8860
9849
|
function normalizeSession(session, key) {
|
|
8861
9850
|
const header = session.delegationHeader;
|
|
8862
9851
|
const jwk = hasPrivateParameter(session.jwk) ? session.jwk : key;
|
|
8863
|
-
if (!
|
|
9852
|
+
if (!isRecord6(header) || typeof header.Authorization !== "string" || typeof session.delegationCid !== "string" || typeof session.spaceId !== "string" || !hasPrivateParameter(jwk) || typeof session.verificationMethod !== "string") {
|
|
8864
9853
|
return void 0;
|
|
8865
9854
|
}
|
|
8866
9855
|
return {
|
|
@@ -8878,7 +9867,7 @@ function normalizeSession(session, key) {
|
|
|
8878
9867
|
}
|
|
8879
9868
|
function normalizeStoredDelegation(entry) {
|
|
8880
9869
|
const raw = entry.delegation;
|
|
8881
|
-
if (!
|
|
9870
|
+
if (!isRecord6(raw) || !isRecord6(raw.delegationHeader)) return void 0;
|
|
8882
9871
|
const expiry = parseExpiry2(raw.expiry);
|
|
8883
9872
|
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") {
|
|
8884
9873
|
return void 0;
|
|
@@ -8890,13 +9879,13 @@ function parseExpiry2(value) {
|
|
|
8890
9879
|
return expiry !== void 0 && !Number.isNaN(expiry.getTime()) ? expiry : void 0;
|
|
8891
9880
|
}
|
|
8892
9881
|
function hasPrivateParameter(value) {
|
|
8893
|
-
return
|
|
9882
|
+
return isRecord6(value) && typeof value.d === "string" && value.d.length > 0;
|
|
8894
9883
|
}
|
|
8895
9884
|
function normalizeDid(value) {
|
|
8896
9885
|
if (typeof value !== "string" || value.length === 0) return void 0;
|
|
8897
9886
|
return value.split("#", 1)[0];
|
|
8898
9887
|
}
|
|
8899
|
-
function
|
|
9888
|
+
function isRecord6(value) {
|
|
8900
9889
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8901
9890
|
}
|
|
8902
9891
|
function failed(context, error) {
|
|
@@ -9301,9 +10290,9 @@ async function invokeOperationWithLocalAuthorityRetry(operationId, operationVers
|
|
|
9301
10290
|
)
|
|
9302
10291
|
);
|
|
9303
10292
|
}
|
|
9304
|
-
const
|
|
9305
|
-
if (
|
|
9306
|
-
const operationContext =
|
|
10293
|
+
const runtimeContext3 = prepared.runtimeResolution.context;
|
|
10294
|
+
if (runtimeContext3.runtime === void 0) return internalOperationErrorResult(prepared);
|
|
10295
|
+
const operationContext = runtimeContext3;
|
|
9307
10296
|
let planned;
|
|
9308
10297
|
try {
|
|
9309
10298
|
planned = exactCapabilities2(await prepared.definition.authority(
|
|
@@ -9508,14 +10497,14 @@ async function prepareInvocation(operationId, operationVersion, invocationTarget
|
|
|
9508
10497
|
}
|
|
9509
10498
|
async function executePreparedInvocation(prepared, options = {}) {
|
|
9510
10499
|
const { operation, definition, parsedInput, runtimeResolution } = prepared;
|
|
9511
|
-
const
|
|
9512
|
-
const resolveSpace2 =
|
|
9513
|
-
|
|
9514
|
-
|
|
10500
|
+
const runtimeContext3 = runtimeResolution.context.runtime === void 0 ? void 0 : runtimeResolution.context;
|
|
10501
|
+
const resolveSpace2 = runtimeContext3 === void 0 ? void 0 : operationSpaceResolver(
|
|
10502
|
+
runtimeContext3.runtime.node,
|
|
10503
|
+
runtimeContext3.summary.space
|
|
9515
10504
|
);
|
|
9516
10505
|
try {
|
|
9517
10506
|
const planned = await definition.authority(
|
|
9518
|
-
|
|
10507
|
+
runtimeContext3 ?? runtimeResolution.context,
|
|
9519
10508
|
parsedInput.data
|
|
9520
10509
|
);
|
|
9521
10510
|
const required = exactCapabilities2(planned);
|
|
@@ -9530,12 +10519,12 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9530
10519
|
);
|
|
9531
10520
|
}
|
|
9532
10521
|
const evaluation = evaluateOperationAuthority(
|
|
9533
|
-
|
|
10522
|
+
runtimeContext3?.runtime.granted ?? [],
|
|
9534
10523
|
required,
|
|
9535
10524
|
resolveSpace2
|
|
9536
10525
|
);
|
|
9537
10526
|
if (!evaluation.satisfied) {
|
|
9538
|
-
if (
|
|
10527
|
+
if (runtimeContext3 === void 0) {
|
|
9539
10528
|
return errorResult(
|
|
9540
10529
|
operation,
|
|
9541
10530
|
runtimeResolution.context.summary,
|
|
@@ -9545,13 +10534,13 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9545
10534
|
if (options.deferAuthorityRequest) {
|
|
9546
10535
|
try {
|
|
9547
10536
|
const request = buildPermissionRequestArtifact({
|
|
9548
|
-
profile:
|
|
9549
|
-
host:
|
|
9550
|
-
sessionDid:
|
|
9551
|
-
posture:
|
|
9552
|
-
operatorType:
|
|
9553
|
-
...
|
|
9554
|
-
...
|
|
10537
|
+
profile: runtimeContext3.summary.profile,
|
|
10538
|
+
host: runtimeContext3.summary.host,
|
|
10539
|
+
sessionDid: runtimeContext3.summary.sessionDid,
|
|
10540
|
+
posture: runtimeContext3.summary.posture,
|
|
10541
|
+
operatorType: runtimeContext3.summary.operatorType ?? "human",
|
|
10542
|
+
...runtimeContext3.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext3.summary.ownerDid },
|
|
10543
|
+
...runtimeContext3.summary.space === void 0 ? {} : { spaceId: runtimeContext3.summary.space },
|
|
9555
10544
|
missing: evaluation.missing
|
|
9556
10545
|
});
|
|
9557
10546
|
return authorityRequiredResult(
|
|
@@ -9560,7 +10549,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9560
10549
|
parsedInput.data,
|
|
9561
10550
|
request,
|
|
9562
10551
|
evaluation.missing,
|
|
9563
|
-
|
|
10552
|
+
runtimeContext3.runtime.node
|
|
9564
10553
|
);
|
|
9565
10554
|
} catch {
|
|
9566
10555
|
return errorResult(
|
|
@@ -9571,7 +10560,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9571
10560
|
}
|
|
9572
10561
|
}
|
|
9573
10562
|
const authority = await persistAuthorityRequest(
|
|
9574
|
-
|
|
10563
|
+
runtimeContext3,
|
|
9575
10564
|
evaluation.missing
|
|
9576
10565
|
);
|
|
9577
10566
|
if (authority.status === "error") {
|
|
@@ -9587,7 +10576,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9587
10576
|
parsedInput.data,
|
|
9588
10577
|
authority.request,
|
|
9589
10578
|
authority.missing,
|
|
9590
|
-
|
|
10579
|
+
runtimeContext3.runtime.node
|
|
9591
10580
|
);
|
|
9592
10581
|
}
|
|
9593
10582
|
const outcome = await definition.execute(
|
|
@@ -9630,7 +10619,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9630
10619
|
)
|
|
9631
10620
|
);
|
|
9632
10621
|
}
|
|
9633
|
-
if (
|
|
10622
|
+
if (runtimeContext3 === void 0) {
|
|
9634
10623
|
return errorResult(
|
|
9635
10624
|
operation,
|
|
9636
10625
|
runtimeResolution.context.summary,
|
|
@@ -9640,13 +10629,13 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9640
10629
|
if (options.deferAuthorityRequest) {
|
|
9641
10630
|
try {
|
|
9642
10631
|
const request = buildPermissionRequestArtifact({
|
|
9643
|
-
profile:
|
|
9644
|
-
host:
|
|
9645
|
-
sessionDid:
|
|
9646
|
-
posture:
|
|
9647
|
-
operatorType:
|
|
9648
|
-
...
|
|
9649
|
-
...
|
|
10632
|
+
profile: runtimeContext3.summary.profile,
|
|
10633
|
+
host: runtimeContext3.summary.host,
|
|
10634
|
+
sessionDid: runtimeContext3.summary.sessionDid,
|
|
10635
|
+
posture: runtimeContext3.summary.posture,
|
|
10636
|
+
operatorType: runtimeContext3.summary.operatorType ?? "human",
|
|
10637
|
+
...runtimeContext3.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext3.summary.ownerDid },
|
|
10638
|
+
...runtimeContext3.summary.space === void 0 ? {} : { spaceId: runtimeContext3.summary.space },
|
|
9650
10639
|
missing: hinted
|
|
9651
10640
|
});
|
|
9652
10641
|
return authorityRequiredResult(
|
|
@@ -9655,7 +10644,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9655
10644
|
parsedInput.data,
|
|
9656
10645
|
request,
|
|
9657
10646
|
hinted,
|
|
9658
|
-
|
|
10647
|
+
runtimeContext3.runtime.node,
|
|
9659
10648
|
outcome.requiresCallerInput ?? false
|
|
9660
10649
|
);
|
|
9661
10650
|
} catch {
|
|
@@ -9667,7 +10656,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9667
10656
|
}
|
|
9668
10657
|
}
|
|
9669
10658
|
const authority = await persistAuthorityRequest(
|
|
9670
|
-
|
|
10659
|
+
runtimeContext3,
|
|
9671
10660
|
hinted,
|
|
9672
10661
|
true
|
|
9673
10662
|
);
|
|
@@ -9684,7 +10673,7 @@ async function executePreparedInvocation(prepared, options = {}) {
|
|
|
9684
10673
|
parsedInput.data,
|
|
9685
10674
|
authority.request,
|
|
9686
10675
|
authority.missing,
|
|
9687
|
-
|
|
10676
|
+
runtimeContext3.runtime.node,
|
|
9688
10677
|
outcome.requiresCallerInput ?? false
|
|
9689
10678
|
);
|
|
9690
10679
|
}
|