@tinycloud/operations 0.4.0-beta.11 → 0.4.0-beta.12

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.
@@ -1,4 +1,4 @@
1
- import { I as InvocationTarget, a as OperationResult } from './contract-eWtDSMeI.cjs';
1
+ import { I as InvocationTarget, a as OperationResult } from './contract-BRwWJpPs.cjs';
2
2
 
3
3
  /**
4
4
  * The only published CLI acquisition helper. Its fixed operation identity is
@@ -1,4 +1,4 @@
1
- import { I as InvocationTarget, a as OperationResult } from './contract-eWtDSMeI.js';
1
+ import { I as InvocationTarget, a as OperationResult } from './contract-BRwWJpPs.js';
2
2
 
3
3
  /**
4
4
  * The only published CLI acquisition helper. Its fixed operation identity is
@@ -3626,6 +3626,32 @@ ORDER BY type, name`;
3626
3626
  }
3627
3627
  });
3628
3628
 
3629
+ // src/contract.ts
3630
+ var STORED_GRANT_SKIP_REASONS, DELEGATION_CID_PATTERN;
3631
+ var init_contract = __esm({
3632
+ "src/contract.ts"() {
3633
+ "use strict";
3634
+ STORED_GRANT_SKIP_REASONS = [
3635
+ "malformed",
3636
+ "unbound",
3637
+ "outside_request",
3638
+ "host_mismatch",
3639
+ "expired",
3640
+ "cid_mismatch",
3641
+ "authority_invalid",
3642
+ "proof_missing",
3643
+ "proof_invalid",
3644
+ "owner_mismatch",
3645
+ "audience_mismatch",
3646
+ "resources_mismatch",
3647
+ "unsupported",
3648
+ "activation_rejected",
3649
+ "invalid"
3650
+ ];
3651
+ DELEGATION_CID_PATTERN = "^bafkr4i[a-z2-7]{52}$";
3652
+ }
3653
+ });
3654
+
3629
3655
  // src/delegation-binding.ts
3630
3656
  import { join as join2 } from "path";
3631
3657
  import * as nodeSdk3 from "@tinycloud/node-sdk";
@@ -3651,12 +3677,12 @@ function replayLimit(entry, migrated) {
3651
3677
  if (binding.success) return binding.data.requested;
3652
3678
  return !migrated && kind === "compact" && !("authorityRequest" in entry) ? "signed" : void 0;
3653
3679
  }
3654
- function bindToSignedCapabilities(record, signed, source, recordedAt = (/* @__PURE__ */ new Date()).toISOString()) {
3680
+ function bindToRequest(record, requested, source, recordedAt = (/* @__PURE__ */ new Date()).toISOString()) {
3655
3681
  return {
3656
3682
  ...record,
3657
3683
  authorityRequest: DelegationRequestBindingSchema.parse({
3658
3684
  requestId: `${REQUEST_ID_PREFIX[source]}:${record.delegation.cid}`,
3659
- requested: structuredClone(signed)
3685
+ requested: structuredClone(requested)
3660
3686
  }),
3661
3687
  authorityRequestAudit: { source, recordedAt, note: BINDING_NOTES[source] }
3662
3688
  };
@@ -3712,23 +3738,40 @@ async function migratedRecord(node, entry, host, recordedAt) {
3712
3738
  const signed = await signedCapabilities(node, delegation, host);
3713
3739
  if (signed === void 0) return void 0;
3714
3740
  try {
3715
- return bindToSignedCapabilities({ ...entry, delegation: { ...entry.delegation, cid: delegation.cid } }, signed, "migration", recordedAt);
3741
+ return bindToRequest({ ...entry, delegation: { ...entry.delegation, cid: delegation.cid } }, signed, "migration", recordedAt);
3716
3742
  } catch {
3717
3743
  return void 0;
3718
3744
  }
3719
3745
  }
3746
+ function skipped(reason) {
3747
+ return { status: "skipped", reason };
3748
+ }
3720
3749
  async function replayStoredDelegation(node, entry, options) {
3750
+ const kind = storedDelegationKind(entry);
3721
3751
  const delegation = normalizeStoredDelegation(entry);
3722
- if (delegation === void 0 || delegation.expiry.getTime() <= Date.now()) return void 0;
3752
+ if (kind === "refused" || delegation === void 0) return skipped("malformed");
3753
+ if (delegation.expiry.getTime() <= Date.now()) return NOT_REPLAYED;
3754
+ if (kind === "other") return skipped("proof_missing");
3723
3755
  const limit = replayLimit(entry, options.migrated);
3724
- if (limit === void 0) return void 0;
3725
- const authorize = limit === "signed" ? () => true : (effective) => delegationWithinRequest(limit, effective, options.resolveSpace);
3756
+ if (limit === void 0) return skipped("unbound");
3757
+ let outsideRequest = false;
3758
+ const authorize = limit === "signed" ? () => true : (effective) => {
3759
+ outsideRequest = !delegationWithinRequest(limit, effective, options.resolveSpace);
3760
+ return !outsideRequest;
3761
+ };
3726
3762
  try {
3727
- return await nodeSdk3.activateValidatedRuntimeDelegation(node, delegation, { host: options.host, authorize });
3728
- } catch {
3729
- return void 0;
3763
+ return {
3764
+ status: "installed",
3765
+ delegation: await nodeSdk3.activateValidatedRuntimeDelegation(node, delegation, { host: options.host, authorize })
3766
+ };
3767
+ } catch (error) {
3768
+ return skipped(outsideRequest ? "outside_request" : rejectionReason(error));
3730
3769
  }
3731
3770
  }
3771
+ function rejectionReason(error) {
3772
+ const reason = isRecord4(error) ? error.reason : void 0;
3773
+ return typeof reason === "string" && STORED_GRANT_SKIP_REASONS.includes(reason) ? reason : "invalid";
3774
+ }
3732
3775
  async function bindingMigrationRecorded(profile) {
3733
3776
  try {
3734
3777
  return await readJson(bindingMigrationPath(profile)) !== null;
@@ -3773,23 +3816,27 @@ function recordKey(entry) {
3773
3816
  function isRecord4(value) {
3774
3817
  return typeof value === "object" && value !== null && !Array.isArray(value);
3775
3818
  }
3776
- var REQUEST_ID_PREFIX, BINDING_NOTES, MIGRATION_LOCK_TIMEOUT_MS;
3819
+ var REQUEST_ID_PREFIX, BINDING_NOTES, MIGRATION_LOCK_TIMEOUT_MS, NOT_REPLAYED;
3777
3820
  var init_delegation_binding = __esm({
3778
3821
  "src/delegation-binding.ts"() {
3779
3822
  "use strict";
3780
3823
  init_artifacts();
3781
3824
  init_authority();
3825
+ init_contract();
3782
3826
  init_state();
3783
3827
  init_secrets();
3784
3828
  REQUEST_ID_PREFIX = {
3785
3829
  migration: "migrated",
3786
- "unbound-import": "unbound-import"
3830
+ "unbound-import": "unbound-import",
3831
+ "cli-grant": "cli-grant"
3787
3832
  };
3788
3833
  BINDING_NOTES = {
3789
3834
  migration: "Stored without a request binding before bindings were required. Bound at migration to exactly its own signed capabilities, so replay refuses any delegation in this record that exceeds them.",
3790
- "unbound-import": "Imported by `tc auth import` without a stored request. Bound to exactly its own signed capabilities, so replay refuses any delegation in this record that exceeds them."
3835
+ "unbound-import": "Imported by `tc auth import` without a stored request. Bound to exactly its own signed capabilities, so replay refuses any delegation in this record that exceeds them.",
3836
+ "cli-grant": "Granted to this CLI by `tc auth request --grant` or a permission escalation, and checked against the request it answered. Bound to exactly its own signed capabilities, so replay refuses any delegation in this record that exceeds them."
3791
3837
  };
3792
3838
  MIGRATION_LOCK_TIMEOUT_MS = 250;
3839
+ NOT_REPLAYED = { status: "not-replayed" };
3793
3840
  }
3794
3841
  });
3795
3842
 
@@ -4202,7 +4249,18 @@ async function createInvocationRuntime(target, requirement = "authenticated") {
4202
4249
  ));
4203
4250
  }
4204
4251
  } else {
4205
- await node.restoreSession(activeSession);
4252
+ try {
4253
+ await node.restoreSession(activeSession);
4254
+ } catch (error) {
4255
+ if (isRecord7(error) && error.code === "AUTH_EXPIRED") {
4256
+ return failed(summary, operationError(
4257
+ "AUTH_REQUIRED",
4258
+ "The stored session has expired or is no longer valid. Sign in again.",
4259
+ { retryable: false }
4260
+ ));
4261
+ }
4262
+ throw error;
4263
+ }
4206
4264
  }
4207
4265
  const activeSessionDid = normalizeDid(node.sessionDid);
4208
4266
  const livePrincipalDid = normalizeDid(node.did);
@@ -4210,6 +4268,7 @@ async function createInvocationRuntime(target, requirement = "authenticated") {
4210
4268
  const livePermissions = [...node.getVerifiedSessionCapabilities()];
4211
4269
  const resolveSpace2 = operationSpaceResolver(node, authenticatedSpace ?? summary.space);
4212
4270
  const seenCids = /* @__PURE__ */ new Set();
4271
+ const warnings = [];
4213
4272
  if (!explicitPrivateKeyOverride) {
4214
4273
  const activator = node;
4215
4274
  const migrated = await prepareStoredDelegationReplay(profileName, activator, {
@@ -4219,20 +4278,25 @@ async function createInvocationRuntime(target, requirement = "authenticated") {
4219
4278
  migrate: activeSession !== void 0
4220
4279
  });
4221
4280
  for (const entry of await readAdditionalDelegations(profileName)) {
4222
- const activated = await replayStoredDelegation(activator, entry, {
4281
+ const replay = await replayStoredDelegation(activator, entry, {
4223
4282
  host: summary.host,
4224
4283
  migrated,
4225
4284
  resolveSpace: resolveSpace2
4226
4285
  });
4227
- if (activated !== void 0 && !seenCids.has(activated.cid)) {
4228
- seenCids.add(activated.cid);
4229
- livePermissions.push(...activated.effectivePermissions);
4286
+ if (replay.status === "installed") {
4287
+ if (!seenCids.has(replay.delegation.cid)) {
4288
+ seenCids.add(replay.delegation.cid);
4289
+ livePermissions.push(...replay.delegation.effectivePermissions);
4290
+ }
4291
+ } else if (replay.status === "skipped") {
4292
+ warnings.push(skippedGrantWarning(node, entry, replay.reason));
4230
4293
  }
4231
4294
  }
4232
4295
  }
4233
4296
  const runtime = {
4234
4297
  node,
4235
- granted: canonicalizeCapabilities(livePermissions)
4298
+ granted: canonicalizeCapabilities(livePermissions),
4299
+ ...warnings.length === 0 ? {} : { warnings }
4236
4300
  };
4237
4301
  return {
4238
4302
  ok: true,
@@ -4256,6 +4320,24 @@ async function createInvocationRuntime(target, requirement = "authenticated") {
4256
4320
  ));
4257
4321
  }
4258
4322
  }
4323
+ function skippedGrantWarning(node, entry, reason) {
4324
+ const grantCid = verifiedStoredCid(node, entry);
4325
+ return { code: "STORED_GRANT_SKIPPED", reason, ...grantCid === void 0 ? {} : { grantCid } };
4326
+ }
4327
+ function verifiedStoredCid(node, entry) {
4328
+ const delegation = isRecord7(entry) && isRecord7(entry.delegation) ? entry.delegation : void 0;
4329
+ const header = isRecord7(delegation?.delegationHeader) ? delegation.delegationHeader : void 0;
4330
+ const cid = delegation?.cid;
4331
+ const computeDelegationCid = isRecord7(node) ? node.computeDelegationCid : void 0;
4332
+ if (typeof cid !== "string" || typeof header?.Authorization !== "string" || typeof computeDelegationCid !== "function") {
4333
+ return void 0;
4334
+ }
4335
+ try {
4336
+ return computeDelegationCid.call(node, header.Authorization) === cid && DELEGATION_CID.test(cid) ? cid : void 0;
4337
+ } catch {
4338
+ return void 0;
4339
+ }
4340
+ }
4259
4341
  function spaceForAuthenticatedPrincipal(principal2) {
4260
4342
  if (principal2 === void 0) return void 0;
4261
4343
  try {
@@ -4304,15 +4386,18 @@ function unresolvedSummary(target) {
4304
4386
  posture: "unauthenticated"
4305
4387
  };
4306
4388
  }
4389
+ var DELEGATION_CID;
4307
4390
  var init_runtime = __esm({
4308
4391
  "src/runtime.ts"() {
4309
4392
  "use strict";
4393
+ init_contract();
4310
4394
  init_authority();
4311
4395
  init_errors();
4312
4396
  init_profile();
4313
4397
  init_secrets();
4314
4398
  init_state();
4315
4399
  init_delegation_binding();
4400
+ DELEGATION_CID = new RegExp(DELEGATION_CID_PATTERN);
4316
4401
  }
4317
4402
  });
4318
4403
 
@@ -4712,6 +4797,9 @@ async function invokeLocalAuthorityRetry(operationId, operationVersion, target,
4712
4797
  unknownInput
4713
4798
  );
4714
4799
  if (isPreparedError(prepared)) return prepared.result;
4800
+ return withRuntimeWarnings(await retryWithLocalAuthority(prepared), prepared);
4801
+ }
4802
+ async function retryWithLocalAuthority(prepared) {
4715
4803
  if (prepared.operation.operationId !== "tinycloud.secrets.get" || prepared.operation.operationVersion !== 1) {
4716
4804
  return errorResult(
4717
4805
  prepared.operation,
@@ -4810,6 +4898,10 @@ async function invokeLocalAuthorityRetry(operationId, operationVersion, target,
4810
4898
  return localAuthorityFailure(prepared);
4811
4899
  }
4812
4900
  }
4901
+ function withRuntimeWarnings(result, prepared) {
4902
+ const warnings = prepared.runtimeResolution.context.runtime?.warnings;
4903
+ return warnings === void 0 || warnings.length === 0 ? result : { ...result, warnings: [...warnings] };
4904
+ }
4813
4905
  function isPreparedError(prepared) {
4814
4906
  return "status" in prepared;
4815
4907
  }