@tinycloud/operations 0.1.0-beta.2 → 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/index.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({ keys });
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(void 0);
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
- { action: "query", sql, params: params ?? [] },
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 = resolveNonSecretSpace(context, input.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 = resolveNonSecretSpace(context, input.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 nodeFailure("list account spaces");
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
- return { status: "ok", output: { spaces, count: spaces.length } };
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 nodeFailure("list account applications");
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
- return { status: "ok", output: { applications, count: applications.length } };
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 = resolveNonSecretSpace(runtime, input.space);
7875
- const result = await runtimeNode(runtime).kvForSpace(space).list(
7876
- input.prefix === void 0 ? void 0 : { prefix: input.prefix }
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: { space, prefix: input.prefix ?? "", keys, count: keys.length }
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 = resolveNonSecretSpace(runtime, input.space);
7895
- const result = await runtimeNode(runtime).kvForSpace(space).get(input.key);
7896
- if (!result.ok) return nodeFailure("read the KV value");
7897
- const encoded = encodeKvValue(result.data.data);
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
- ...result.data.headers.etag === void 0 ? {} : { etag: result.data.headers.etag },
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 resolveNonSecretSpace(context, space) {
8114
+ function resolveGenericKvSpace(context, space) {
7933
8115
  const resolved = resolveSpace(context, space);
7934
- if (resolved.split(":").at(-1)?.toLowerCase() === "secrets") {
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 the TinyCloud secrets space; use tinycloud.secrets.get."
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
- if (!loaded.ok || !isRecord2(loaded.data.data)) return { ok: false };
7952
- records.push({ key, value: loaded.data.data });
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 (value instanceof Uint8Array) {
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
- value,
8004
- encoding: typeof value === "string" ? "text" : "json"
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: z4.object({
8090
- etag: z4.string().optional(),
8091
- contentType: z4.string().optional(),
8092
- lastModified: z4.string().optional(),
8093
- contentLength: z4.number().int().nonnegative().optional()
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 from a delegated non-secrets TinyCloud space.",
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/status.ts
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 isRecord3(storedProfile);
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 (!isRecord3(session)) throw new TypeError("Invalid session store.");
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 (!isRecord3(entry) || !isRecord3(entry.delegation) || !("expiry" in entry.delegation)) {
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 isRecord3(value) {
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 = z6.object({}).strict();
8525
- StatusOutputSchema = z6.object({
8526
- profile: z6.string().min(1),
8527
- host: z6.string().min(1),
8528
- posture: z6.enum([
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: z6.enum(["human", "agent"]).optional(),
8535
- principalDid: z6.string().min(1).optional(),
8536
- sessionDid: z6.string().min(1).optional(),
8537
- ownerDid: z6.string().min(1).optional(),
8538
- space: z6.string().min(1).optional(),
8539
- session: z6.object({
8540
- present: z6.boolean(),
8541
- expired: z6.boolean().nullable(),
8542
- expiresAt: z6.string().datetime({ offset: true }).nullable()
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: z6.number().int().nonnegative()
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 isRecord4(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);
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 isRecord4(value) {
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 (!isRecord5(header) || typeof header.Authorization !== "string" || typeof session.delegationCid !== "string" || typeof session.spaceId !== "string" || !hasPrivateParameter(jwk) || typeof session.verificationMethod !== "string") {
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 (!isRecord5(raw) || !isRecord5(raw.delegationHeader)) return void 0;
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 isRecord5(value) && typeof value.d === "string" && value.d.length > 0;
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 isRecord5(value) {
9888
+ function isRecord6(value) {
8900
9889
  return typeof value === "object" && value !== null && !Array.isArray(value);
8901
9890
  }
8902
9891
  function failed(context, error) {
@@ -9394,14 +10383,14 @@ async function prepareInvocation(operationId, operationVersion, invocationTarget
9394
10383
  }
9395
10384
  async function executePreparedInvocation(prepared, options = {}) {
9396
10385
  const { operation, definition, parsedInput, runtimeResolution } = prepared;
9397
- const runtimeContext2 = runtimeResolution.context.runtime === void 0 ? void 0 : runtimeResolution.context;
9398
- const resolveSpace2 = runtimeContext2 === void 0 ? void 0 : operationSpaceResolver(
9399
- runtimeContext2.runtime.node,
9400
- runtimeContext2.summary.space
10386
+ const runtimeContext3 = runtimeResolution.context.runtime === void 0 ? void 0 : runtimeResolution.context;
10387
+ const resolveSpace2 = runtimeContext3 === void 0 ? void 0 : operationSpaceResolver(
10388
+ runtimeContext3.runtime.node,
10389
+ runtimeContext3.summary.space
9401
10390
  );
9402
10391
  try {
9403
10392
  const planned = await definition.authority(
9404
- runtimeContext2 ?? runtimeResolution.context,
10393
+ runtimeContext3 ?? runtimeResolution.context,
9405
10394
  parsedInput.data
9406
10395
  );
9407
10396
  const required = exactCapabilities2(planned);
@@ -9416,12 +10405,12 @@ async function executePreparedInvocation(prepared, options = {}) {
9416
10405
  );
9417
10406
  }
9418
10407
  const evaluation = evaluateOperationAuthority(
9419
- runtimeContext2?.runtime.granted ?? [],
10408
+ runtimeContext3?.runtime.granted ?? [],
9420
10409
  required,
9421
10410
  resolveSpace2
9422
10411
  );
9423
10412
  if (!evaluation.satisfied) {
9424
- if (runtimeContext2 === void 0) {
10413
+ if (runtimeContext3 === void 0) {
9425
10414
  return errorResult(
9426
10415
  operation,
9427
10416
  runtimeResolution.context.summary,
@@ -9431,13 +10420,13 @@ async function executePreparedInvocation(prepared, options = {}) {
9431
10420
  if (options.deferAuthorityRequest) {
9432
10421
  try {
9433
10422
  const request = buildPermissionRequestArtifact({
9434
- profile: runtimeContext2.summary.profile,
9435
- host: runtimeContext2.summary.host,
9436
- sessionDid: runtimeContext2.summary.sessionDid,
9437
- posture: runtimeContext2.summary.posture,
9438
- operatorType: runtimeContext2.summary.operatorType ?? "human",
9439
- ...runtimeContext2.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext2.summary.ownerDid },
9440
- ...runtimeContext2.summary.space === void 0 ? {} : { spaceId: runtimeContext2.summary.space },
10423
+ profile: runtimeContext3.summary.profile,
10424
+ host: runtimeContext3.summary.host,
10425
+ sessionDid: runtimeContext3.summary.sessionDid,
10426
+ posture: runtimeContext3.summary.posture,
10427
+ operatorType: runtimeContext3.summary.operatorType ?? "human",
10428
+ ...runtimeContext3.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext3.summary.ownerDid },
10429
+ ...runtimeContext3.summary.space === void 0 ? {} : { spaceId: runtimeContext3.summary.space },
9441
10430
  missing: evaluation.missing
9442
10431
  });
9443
10432
  return authorityRequiredResult(
@@ -9446,7 +10435,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9446
10435
  parsedInput.data,
9447
10436
  request,
9448
10437
  evaluation.missing,
9449
- runtimeContext2.runtime.node
10438
+ runtimeContext3.runtime.node
9450
10439
  );
9451
10440
  } catch {
9452
10441
  return errorResult(
@@ -9457,7 +10446,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9457
10446
  }
9458
10447
  }
9459
10448
  const authority = await persistAuthorityRequest(
9460
- runtimeContext2,
10449
+ runtimeContext3,
9461
10450
  evaluation.missing
9462
10451
  );
9463
10452
  if (authority.status === "error") {
@@ -9473,7 +10462,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9473
10462
  parsedInput.data,
9474
10463
  authority.request,
9475
10464
  authority.missing,
9476
- runtimeContext2.runtime.node
10465
+ runtimeContext3.runtime.node
9477
10466
  );
9478
10467
  }
9479
10468
  const outcome = await definition.execute(
@@ -9516,7 +10505,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9516
10505
  )
9517
10506
  );
9518
10507
  }
9519
- if (runtimeContext2 === void 0) {
10508
+ if (runtimeContext3 === void 0) {
9520
10509
  return errorResult(
9521
10510
  operation,
9522
10511
  runtimeResolution.context.summary,
@@ -9526,13 +10515,13 @@ async function executePreparedInvocation(prepared, options = {}) {
9526
10515
  if (options.deferAuthorityRequest) {
9527
10516
  try {
9528
10517
  const request = buildPermissionRequestArtifact({
9529
- profile: runtimeContext2.summary.profile,
9530
- host: runtimeContext2.summary.host,
9531
- sessionDid: runtimeContext2.summary.sessionDid,
9532
- posture: runtimeContext2.summary.posture,
9533
- operatorType: runtimeContext2.summary.operatorType ?? "human",
9534
- ...runtimeContext2.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext2.summary.ownerDid },
9535
- ...runtimeContext2.summary.space === void 0 ? {} : { spaceId: runtimeContext2.summary.space },
10518
+ profile: runtimeContext3.summary.profile,
10519
+ host: runtimeContext3.summary.host,
10520
+ sessionDid: runtimeContext3.summary.sessionDid,
10521
+ posture: runtimeContext3.summary.posture,
10522
+ operatorType: runtimeContext3.summary.operatorType ?? "human",
10523
+ ...runtimeContext3.summary.ownerDid === void 0 ? {} : { ownerDid: runtimeContext3.summary.ownerDid },
10524
+ ...runtimeContext3.summary.space === void 0 ? {} : { spaceId: runtimeContext3.summary.space },
9536
10525
  missing: hinted
9537
10526
  });
9538
10527
  return authorityRequiredResult(
@@ -9541,7 +10530,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9541
10530
  parsedInput.data,
9542
10531
  request,
9543
10532
  hinted,
9544
- runtimeContext2.runtime.node,
10533
+ runtimeContext3.runtime.node,
9545
10534
  outcome.requiresCallerInput ?? false
9546
10535
  );
9547
10536
  } catch {
@@ -9553,7 +10542,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9553
10542
  }
9554
10543
  }
9555
10544
  const authority = await persistAuthorityRequest(
9556
- runtimeContext2,
10545
+ runtimeContext3,
9557
10546
  hinted,
9558
10547
  true
9559
10548
  );
@@ -9570,7 +10559,7 @@ async function executePreparedInvocation(prepared, options = {}) {
9570
10559
  parsedInput.data,
9571
10560
  authority.request,
9572
10561
  authority.missing,
9573
- runtimeContext2.runtime.node,
10562
+ runtimeContext3.runtime.node,
9574
10563
  outcome.requiresCallerInput ?? false
9575
10564
  );
9576
10565
  }