@dragonmastery/tamer 0.40.1 → 0.42.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.
Files changed (97) hide show
  1. package/README.md +10 -11
  2. package/dist/{apply-CV4_3Jv4.mjs → apply-Mk9usR-U.mjs} +14 -14
  3. package/dist/{apply-CV4_3Jv4.mjs.map → apply-Mk9usR-U.mjs.map} +1 -1
  4. package/dist/{applyTarget-B1YPgkb3.mjs → applyTarget-CJSn9DeJ.mjs} +3 -3
  5. package/dist/{applyTarget-B1YPgkb3.mjs.map → applyTarget-CJSn9DeJ.mjs.map} +1 -1
  6. package/dist/{bootstrap-ilkixdmD.mjs → bootstrap-BCy6B-B6.mjs} +3 -3
  7. package/dist/{bootstrap-ilkixdmD.mjs.map → bootstrap-BCy6B-B6.mjs.map} +1 -1
  8. package/dist/{cloudflareSnapshot-BAeNVohz.mjs → cloudflareSnapshot-DqP8v_xG.mjs} +4 -4
  9. package/dist/{cloudflareSnapshot-BAeNVohz.mjs.map → cloudflareSnapshot-DqP8v_xG.mjs.map} +1 -1
  10. package/dist/{deploy-BEaNADU6.mjs → deploy-DbXBHpCG.mjs} +9 -9
  11. package/dist/{deploy-BEaNADU6.mjs.map → deploy-DbXBHpCG.mjs.map} +1 -1
  12. package/dist/{destroy-Krf35oqE.mjs → destroy-CesVkyxf.mjs} +10 -10
  13. package/dist/{destroy-Krf35oqE.mjs.map → destroy-CesVkyxf.mjs.map} +1 -1
  14. package/dist/{destroy-tenant-C95ljuon.mjs → destroy-tenant-DMynv_u-.mjs} +1 -1
  15. package/dist/{destroy-tenant-C95ljuon.mjs.map → destroy-tenant-DMynv_u-.mjs.map} +1 -1
  16. package/dist/{dev-C__1rLos.mjs → dev-sk6JGKe4.mjs} +7 -7
  17. package/dist/{dev-C__1rLos.mjs.map → dev-sk6JGKe4.mjs.map} +1 -1
  18. package/dist/{dns-records.resolve-DwBR_1WI.mjs → dns-records.resolve-SPYGYNHa.mjs} +1 -1
  19. package/dist/{dns-records.resolve-DwBR_1WI.mjs.map → dns-records.resolve-SPYGYNHa.mjs.map} +1 -1
  20. package/dist/{dns-records.resolve-C2T0m4NG.mjs → dns-records.resolve-jECsH6N-.mjs} +1 -1
  21. package/dist/{dns-records.sync-Dfwk76J_.mjs → dns-records.sync-BORRvLky.mjs} +2 -2
  22. package/dist/{dns-records.sync-Dfwk76J_.mjs.map → dns-records.sync-BORRvLky.mjs.map} +1 -1
  23. package/dist/{doctor-BIaLEVFR.mjs → doctor-BgqnscIE.mjs} +1 -1
  24. package/dist/{doctor-BIaLEVFR.mjs.map → doctor-BgqnscIE.mjs.map} +1 -1
  25. package/dist/{drift-CLsSBorO.mjs → drift-C5r1cKxV.mjs} +6 -6
  26. package/dist/{drift-CLsSBorO.mjs.map → drift-C5r1cKxV.mjs.map} +1 -1
  27. package/dist/drift-oOUlh0u8.mjs +8 -0
  28. package/dist/{emit-Dh68dvo5.mjs → emit-C7KXAVP0.mjs} +2 -2
  29. package/dist/{emit-Dh68dvo5.mjs.map → emit-C7KXAVP0.mjs.map} +1 -1
  30. package/dist/{env-gc-0vX5Av4i.mjs → env-gc-DE4EV7j7.mjs} +10 -10
  31. package/dist/{env-gc-0vX5Av4i.mjs.map → env-gc-DE4EV7j7.mjs.map} +1 -1
  32. package/dist/{env-list-DYCprcLb.mjs → env-list-DKseThiA.mjs} +1 -1
  33. package/dist/{env-list-DYCprcLb.mjs.map → env-list-DKseThiA.mjs.map} +1 -1
  34. package/dist/{events-CnWvxyX_.mjs → events-CqbN9sbT.mjs} +1 -1
  35. package/dist/{events-CnWvxyX_.mjs.map → events-CqbN9sbT.mjs.map} +1 -1
  36. package/dist/{generator-DAU5K77L.mjs → generator-CbH3UZ3K.mjs} +2 -2
  37. package/dist/{generator-DAU5K77L.mjs.map → generator-CbH3UZ3K.mjs.map} +1 -1
  38. package/dist/{import-BNbHjR9t.mjs → import-leVD9Ryg.mjs} +5 -5
  39. package/dist/{import-BNbHjR9t.mjs.map → import-leVD9Ryg.mjs.map} +1 -1
  40. package/dist/loader-B5iVsP6t.mjs +3 -0
  41. package/dist/{logpush-job-C_6uzGUC.mjs → logpush-job-Dqlt-wEw.mjs} +2 -2
  42. package/dist/{logpush-job-C_6uzGUC.mjs.map → logpush-job-Dqlt-wEw.mjs.map} +1 -1
  43. package/dist/{migrate-EVfFlJOM.mjs → migrate-DyrTw9ep.mjs} +5 -5
  44. package/dist/{migrate-EVfFlJOM.mjs.map → migrate-DyrTw9ep.mjs.map} +1 -1
  45. package/dist/{plan-tnUWkiM1.mjs → plan-D7UyLznb.mjs} +11 -11
  46. package/dist/{plan-tnUWkiM1.mjs.map → plan-D7UyLznb.mjs.map} +1 -1
  47. package/dist/{planFormat-DpA8XhzX.mjs → planFormat-CJw8Kq2s.mjs} +1 -1
  48. package/dist/{planFormat-DpA8XhzX.mjs.map → planFormat-CJw8Kq2s.mjs.map} +1 -1
  49. package/dist/{provision-tenant-R6Xa3IUJ.mjs → provision-tenant-BZpqekMK.mjs} +77 -28
  50. package/dist/provision-tenant-BZpqekMK.mjs.map +1 -0
  51. package/dist/{r2S3EmptyBucket-CXLmOrYF.mjs → r2S3EmptyBucket-DD81ZWQ7.mjs} +1 -1
  52. package/dist/{r2S3EmptyBucket-CXLmOrYF.mjs.map → r2S3EmptyBucket-DD81ZWQ7.mjs.map} +1 -1
  53. package/dist/{registry-X9dlQxG3.mjs → registry-CTerXUza.mjs} +81 -33
  54. package/dist/registry-CTerXUza.mjs.map +1 -0
  55. package/dist/{resolveTenantBindings-4grVKHIG.mjs → resolveTenantBindings-86AmRQcW.mjs} +18 -11
  56. package/dist/resolveTenantBindings-86AmRQcW.mjs.map +1 -0
  57. package/dist/{stackOutputs-CU2oxjpU.mjs → stackOutputs-BLp-dyzl.mjs} +1 -1
  58. package/dist/{stackOutputs-CU2oxjpU.mjs.map → stackOutputs-BLp-dyzl.mjs.map} +1 -1
  59. package/dist/{status-srUxsBIB.mjs → status-CL4MEGbn.mjs} +6 -6
  60. package/dist/{status-srUxsBIB.mjs.map → status-CL4MEGbn.mjs.map} +1 -1
  61. package/dist/sync-DSgJGQh1.mjs +7 -0
  62. package/dist/{sync-DfJGkOME.mjs → sync-Dii9n2nJ.mjs} +5 -5
  63. package/dist/{sync-DfJGkOME.mjs.map → sync-Dii9n2nJ.mjs.map} +1 -1
  64. package/dist/tamer.mjs +63 -22
  65. package/dist/tamer.mjs.map +1 -1
  66. package/dist/{tamerArtifactsR2-B9myb-IA.mjs → tamerArtifactsR2-B3X21TGV.mjs} +2 -2
  67. package/dist/{tamerArtifactsR2-B9myb-IA.mjs.map → tamerArtifactsR2-B3X21TGV.mjs.map} +1 -1
  68. package/dist/{tenant-migrate-BfvYL0HH.mjs → tenant-migrate-CM6cb1zo.mjs} +15 -17
  69. package/dist/tenant-migrate-CM6cb1zo.mjs.map +1 -0
  70. package/dist/{types-BPxuutXk.mjs → types-DCL0mEjS.mjs} +5 -5
  71. package/dist/{types-BPxuutXk.mjs.map → types-DCL0mEjS.mjs.map} +1 -1
  72. package/dist/{verifyPlanFile-CoAOsD3W.mjs → verifyPlanFile-B9VCcFIJ.mjs} +2 -2
  73. package/dist/{verifyPlanFile-CoAOsD3W.mjs.map → verifyPlanFile-B9VCcFIJ.mjs.map} +1 -1
  74. package/dist/{wfp-put-BBitXJep.mjs → wfp-put-Bl5K3snx.mjs} +25 -3
  75. package/dist/wfp-put-Bl5K3snx.mjs.map +1 -0
  76. package/dist/{worker-route-CvuUPq1k.mjs → worker-route-BapxsQyX.mjs} +2 -2
  77. package/dist/{worker-route-CvuUPq1k.mjs.map → worker-route-BapxsQyX.mjs.map} +1 -1
  78. package/dist/{workers-DSlrKeNL.mjs → workers-D7ow_joN.mjs} +7 -13
  79. package/dist/{workers-DSlrKeNL.mjs.map → workers-D7ow_joN.mjs.map} +1 -1
  80. package/dist/wranglerSpawn-CfPkFLP3.mjs +3 -0
  81. package/dist/{wranglerSpawn-DWdgrsmQ.mjs → wranglerSpawn-VkSL0gZd.mjs} +1 -1
  82. package/dist/{wranglerSpawn-DWdgrsmQ.mjs.map → wranglerSpawn-VkSL0gZd.mjs.map} +1 -1
  83. package/dist/{zoneResolver-VoxLHM4N.mjs → zoneResolver-CamXJpSB.mjs} +1 -1
  84. package/dist/{zoneResolver-VoxLHM4N.mjs.map → zoneResolver-CamXJpSB.mjs.map} +1 -1
  85. package/package.json +5 -2
  86. package/dist/buildDispatchUploadForm-D_fM8JaL.mjs +0 -35
  87. package/dist/buildDispatchUploadForm-D_fM8JaL.mjs.map +0 -1
  88. package/dist/drift-08k11FV6.mjs +0 -8
  89. package/dist/provision-tenant-R6Xa3IUJ.mjs.map +0 -1
  90. package/dist/registry-X9dlQxG3.mjs.map +0 -1
  91. package/dist/resolveTenantBindings-4grVKHIG.mjs.map +0 -1
  92. package/dist/sync-CfNyelDN.mjs +0 -7
  93. package/dist/tenant-migrate-BfvYL0HH.mjs.map +0 -1
  94. package/dist/wfp-put-BBitXJep.mjs.map +0 -1
  95. package/dist/wranglerSpawn-aARBLHpA.mjs +0 -3
  96. /package/dist/{secrets-2Hy5LMHs.mjs → secrets-DJ1yUy01.mjs} +0 -0
  97. /package/dist/{wranglerOutFile-f08VsoAj.mjs → wranglerOutFile-DDFKeKwO.mjs} +0 -0
@@ -1,6 +1,7 @@
1
1
  import { H as getWorkers } from "./tamer.mjs";
2
- import { n as r2S3CredentialsFromEnv, t as emptyR2BucketViaS3 } from "./r2S3EmptyBucket-CXLmOrYF.mjs";
3
- import { n as logApplyChange } from "./planFormat-DpA8XhzX.mjs";
2
+ import { t as emptyR2BucketViaS3 } from "./r2S3EmptyBucket-DD81ZWQ7.mjs";
3
+ import { n as logApplyChange } from "./planFormat-CJw8Kq2s.mjs";
4
+ import { createHash } from "crypto";
4
5
 
5
6
  //#region src/core/naming/resolveCloudflareName.ts
6
7
  function resolveOverride(fn, tenantId, env, ctx) {
@@ -667,21 +668,71 @@ function r2Drift(allR2, resources, env, state, naming) {
667
668
  }
668
669
 
669
670
  //#endregion
670
- //#region src/features/r2/r2CfApiEmptyBucket.ts
671
- async function emptyR2BucketViaCfApi(api, bucketName) {
672
- let cursor;
673
- let objectsDeleted = 0;
674
- for (;;) {
675
- const { objects, cursor: nextCursor } = await api.r2ListObjects(bucketName, cursor);
676
- if (objects.length === 0 && !nextCursor) break;
677
- for (const obj of objects) {
678
- await api.r2DeleteObject(bucketName, obj.key);
679
- objectsDeleted += 1;
680
- }
681
- if (!nextCursor) break;
682
- cursor = nextCursor;
671
+ //#region src/features/r2/r2TempS3Creds.ts
672
+ /**
673
+ * Find the "Workers R2 Storage Bucket Item Write" permission group ID.
674
+ * This is the bucket-scoped permission that maps to S3 operations.
675
+ */
676
+ async function findR2BucketItemWriteGroupId(api) {
677
+ const groups = await api.accountTokenPermissionGroupsListAll();
678
+ for (const g of groups) {
679
+ const name = g.name.toLowerCase();
680
+ if (/workers r2 storage/i.test(name) && /bucket item/i.test(name) && /write|edit/i.test(name)) return g.id;
683
681
  }
684
- return { objectsDeleted };
682
+ throw new Error("Could not find 'Workers R2 Storage Bucket Item Write' permission group. Available: " + groups.slice(0, 12).map((g) => g.name).join(", "));
683
+ }
684
+ /**
685
+ * Mint a temporary R2 S3 credential for a specific bucket.
686
+ * Returns S3-compatible credentials + the token ID (for cleanup).
687
+ *
688
+ * Uses the same permission group and resource format as the Cloudflare
689
+ * dashboard when creating R2 API tokens:
690
+ * group: "Workers R2 Storage Bucket Item Write"
691
+ * resource: "com.cloudflare.edge.r2.bucket.{accountId}_default_{bucketName}"
692
+ */
693
+ async function mintR2S3Credentials(api, accountId, bucketName) {
694
+ const groupId = await findR2BucketItemWriteGroupId(api);
695
+ const bucketResource = `com.cloudflare.edge.r2.bucket.${accountId}_default_${bucketName}`;
696
+ const tokenName = `Tamer R2 cleanup ${bucketName} ${Date.now()}`;
697
+ console.log(`R2: minting S3 token — group=${groupId}, resource=${bucketResource}`);
698
+ const result = await api.accountTokenCreate({
699
+ name: tokenName,
700
+ policies: [{
701
+ effect: "allow",
702
+ permission_groups: [{ id: groupId }],
703
+ resources: { [bucketResource]: "*" }
704
+ }],
705
+ condition: {}
706
+ });
707
+ if (!result.value) {
708
+ try {
709
+ await api.accountTokenDelete(result.id);
710
+ } catch {}
711
+ throw new Error("R2 S3 cleanup: token create succeeded but no value returned. Check that the CF API token has 'API Tokens: Edit' permission.");
712
+ }
713
+ if (!result.policies?.[0]?.id) {
714
+ try {
715
+ await api.accountTokenDelete(result.id);
716
+ } catch {}
717
+ throw new Error("R2 S3 cleanup: token create succeeded but no policy id returned.");
718
+ }
719
+ const policyId = result.policies?.[0]?.id;
720
+ console.log(`R2: token created — id=${result.id}, policyId=${policyId}, valuePrefix=${result.value?.slice(0, 12)}…`);
721
+ const secretAccessKey = createHash("sha256").update(result.value).digest("hex");
722
+ console.log(`R2: derived secret — prefix=${secretAccessKey.slice(0, 16)}…`);
723
+ return {
724
+ accessKeyId: policyId,
725
+ secretAccessKey,
726
+ tokenId: result.id
727
+ };
728
+ }
729
+ /**
730
+ * Delete a previously minted temporary R2 S3 token.
731
+ */
732
+ async function deleteR2S3Credentials(api, tokenId) {
733
+ try {
734
+ await api.accountTokenDelete(tokenId);
735
+ } catch {}
685
736
  }
686
737
 
687
738
  //#endregion
@@ -691,38 +742,35 @@ async function r2Destroy(_env, state, api, config, baseDir, _force) {
691
742
  const resources = state.getAll();
692
743
  const r2Entries = Object.values(resources).filter((e) => e.type === "r2_bucket");
693
744
  const accountId = api.getAccountId();
694
- const s3creds = r2S3CredentialsFromEnv();
695
745
  for (const entry of r2Entries) {
696
746
  if (!owned.has(entry.logicalName)) continue;
697
747
  const name = entry.derivedName;
698
- if (s3creds) try {
699
- console.log(`R2: emptying bucket "${name}" via S3 API…`);
700
- const { uploadsAborted, objectsDeleted } = await emptyR2BucketViaS3(accountId, name, s3creds);
748
+ let creds = null;
749
+ try {
750
+ creds = await mintR2S3Credentials(api, accountId, name);
751
+ } catch {}
752
+ if (creds) try {
753
+ const { uploadsAborted, objectsDeleted } = await emptyR2BucketViaS3(accountId, name, {
754
+ accessKeyId: creds.accessKeyId,
755
+ secretAccessKey: creds.secretAccessKey
756
+ });
701
757
  console.log(`R2: bucket "${name}" — aborted ${uploadsAborted} multipart upload(s), deleted ${objectsDeleted} object(s).`);
702
758
  } catch (err) {
703
- console.warn(`R2: S3 empty failed for "${name}", trying CF API:`, err instanceof Error ? err.message : err);
704
- await tryEmptyViaCfApi(api, name);
759
+ console.warn(`R2: S3 empty failed for "${name}":`, err instanceof Error ? err.message : err);
705
760
  }
706
- else await tryEmptyViaCfApi(api, name);
707
761
  try {
708
762
  await api.r2Delete(name);
709
763
  state.delete(name);
764
+ console.log(`R2: deleted bucket "${name}".`);
710
765
  } catch (err) {
711
766
  const msg = err instanceof Error ? err.message : String(err);
712
767
  if (/404|not found/i.test(msg)) state.delete(name);
713
768
  else throw err;
769
+ } finally {
770
+ if (creds) await deleteR2S3Credentials(api, creds.tokenId);
714
771
  }
715
772
  }
716
773
  }
717
- async function tryEmptyViaCfApi(api, bucketName) {
718
- try {
719
- console.log(`R2: emptying bucket "${bucketName}" via CF API…`);
720
- const { objectsDeleted } = await emptyR2BucketViaCfApi(api, bucketName);
721
- console.log(`R2: bucket "${bucketName}" — deleted ${objectsDeleted} object(s) via CF API.`);
722
- } catch (err) {
723
- console.warn(`R2: CF API empty failed for "${bucketName}" (bucket may have objects that prevent deletion):`, err instanceof Error ? err.message : err);
724
- }
725
- }
726
774
 
727
775
  //#endregion
728
776
  //#region src/features/r2/r2.generate.ts
@@ -3109,4 +3157,4 @@ function getResourceModule(kind) {
3109
3157
 
3110
3158
  //#endregion
3111
3159
  export { logicalNamesForResourceKind as a, workflowsApply as i, resourceModules as n, d1CloudflareDatabaseName as o, secretsStoreDeriveName as r, d1SkipsProvisionAndMigrate as s, getResourceModule as t };
3112
- //# sourceMappingURL=registry-X9dlQxG3.mjs.map
3160
+ //# sourceMappingURL=registry-CTerXUza.mjs.map