@homeflare/alchemy 0.35.0 → 0.37.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/README.md +14 -0
- package/dist/argocd/cluster.d.ts +102 -0
- package/dist/argocd/cluster.d.ts.map +1 -0
- package/dist/argocd/credentials.d.ts +37 -0
- package/dist/argocd/credentials.d.ts.map +1 -0
- package/dist/argocd/fake-argocd.d.ts +42 -0
- package/dist/argocd/fake-argocd.d.ts.map +1 -0
- package/dist/argocd/git-credentials.d.ts +29 -0
- package/dist/argocd/git-credentials.d.ts.map +1 -0
- package/dist/argocd/index.d.ts +19 -0
- package/dist/argocd/index.d.ts.map +1 -0
- package/dist/argocd/index.js +306 -0
- package/dist/argocd/index.js.map +17 -0
- package/dist/argocd/providers.d.ts +13 -0
- package/dist/argocd/providers.d.ts.map +1 -0
- package/dist/argocd/repo-creds.d.ts +67 -0
- package/dist/argocd/repo-creds.d.ts.map +1 -0
- package/dist/argocd/repository.d.ts +87 -0
- package/dist/argocd/repository.d.ts.map +1 -0
- package/dist/argocd/resource.d.ts +90 -0
- package/dist/argocd/resource.d.ts.map +1 -0
- package/dist/cloudflare/index.js +4 -4
- package/dist/cloudflare/index.js.map +3 -3
- package/dist/cloudflare/r2-bucket-lock.d.ts +14 -5
- package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -1
- package/dist/grafana/index.d.ts +5 -4
- package/dist/grafana/index.d.ts.map +1 -1
- package/dist/grafana/index.js +204 -90
- package/dist/grafana/index.js.map +7 -4
- package/dist/grafana/notification-policy-drop-warning.d.ts +27 -0
- package/dist/grafana/notification-policy-drop-warning.d.ts.map +1 -0
- package/dist/grafana/notification-policy-fixtures.d.ts +34 -0
- package/dist/grafana/notification-policy-fixtures.d.ts.map +1 -0
- package/dist/grafana/notification-policy-model.d.ts +53 -0
- package/dist/grafana/notification-policy-model.d.ts.map +1 -0
- package/dist/grafana/notification-policy.d.ts +57 -0
- package/dist/grafana/notification-policy.d.ts.map +1 -0
- package/dist/grafana/providers.d.ts +1 -1
- package/dist/grafana/providers.d.ts.map +1 -1
- package/dist/litellm/index.js.map +2 -2
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-form.d.ts +4 -5
- package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-wire.d.ts +33 -0
- package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-daemon.d.ts +35 -0
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-distilled.d.ts +14 -0
- package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -0
- package/dist/proxmox/ceph-fs-wire.d.ts +20 -11
- package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts +31 -6
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-tree.d.ts +12 -3
- package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +17 -2
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd.d.ts +6 -0
- package/dist/proxmox/ceph-osd.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-settle.d.ts +10 -4
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts +46 -0
- package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool.d.ts +10 -5
- package/dist/proxmox/ceph-pool.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +1 -1
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +611 -477
- package/dist/proxmox/index.js.map +15 -12
- package/dist/proxmox/storage-wire.d.ts +8 -1
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/user-wire.d.ts +1 -1
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/docs/argocd-kubernetes.md +100 -0
- package/docs/argocd.md +139 -0
- package/docs/credentials.md +9 -0
- package/docs/grafana-alerting.md +3 -2
- package/docs/grafana-notification-policy.md +127 -0
- package/docs/grafana.md +12 -8
- package/docs/litellm.md +17 -0
- package/docs/peers.md +7 -0
- package/docs/unifi.md +45 -0
- package/docs/upstream-conformance.md +19 -5
- package/package.json +8 -3
- package/src/argocd/cluster.test.ts +120 -0
- package/src/argocd/cluster.ts +222 -0
- package/src/argocd/credentials.ts +38 -0
- package/src/argocd/fake-argocd.ts +60 -0
- package/src/argocd/git-credentials.ts +71 -0
- package/src/argocd/index.ts +40 -0
- package/src/argocd/providers.ts +17 -0
- package/src/argocd/repo-creds.test.ts +123 -0
- package/src/argocd/repo-creds.ts +115 -0
- package/src/argocd/repository.test.ts +167 -0
- package/src/argocd/repository.ts +165 -0
- package/src/argocd/resource.ts +150 -0
- package/src/cloudflare/r2-bucket-lock.test.ts +54 -18
- package/src/cloudflare/r2-bucket-lock.ts +25 -18
- package/src/grafana/index.ts +11 -4
- package/src/grafana/notification-policy-drop-warning.test.ts +163 -0
- package/src/grafana/notification-policy-drop-warning.ts +60 -0
- package/src/grafana/notification-policy-fixtures.ts +27 -0
- package/src/grafana/notification-policy-model.test.ts +104 -0
- package/src/grafana/notification-policy-model.ts +100 -0
- package/src/grafana/notification-policy-refusals.test.ts +119 -0
- package/src/grafana/notification-policy.test.ts +86 -0
- package/src/grafana/notification-policy.ts +191 -0
- package/src/grafana/providers.ts +2 -0
- package/src/litellm/operations.ts +8 -4
- package/src/proxmox/ceph-daemon-form.ts +7 -8
- package/src/proxmox/ceph-daemon-wire.ts +115 -0
- package/src/proxmox/ceph-daemon-write.test.ts +158 -0
- package/src/proxmox/ceph-daemon.ts +65 -47
- package/src/proxmox/ceph-fs-delete.test.ts +81 -0
- package/src/proxmox/ceph-fs-distilled.ts +102 -0
- package/src/proxmox/ceph-fs-wire.ts +17 -31
- package/src/proxmox/ceph-fs-write.test.ts +67 -0
- package/src/proxmox/ceph-fs.ts +66 -69
- package/src/proxmox/ceph-osd-tree.ts +14 -5
- package/src/proxmox/ceph-osd-write.test.ts +61 -0
- package/src/proxmox/ceph-osd-write.ts +33 -6
- package/src/proxmox/ceph-osd.ts +6 -0
- package/src/proxmox/ceph-pool-settle.ts +13 -7
- package/src/proxmox/ceph-pool-wire.ts +110 -0
- package/src/proxmox/ceph-pool-write.test.ts +145 -0
- package/src/proxmox/ceph-pool.ts +87 -98
- package/src/proxmox/distilled-task-await.test.ts +0 -124
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cloudflare/r2-bucket-lock.ts", "../src/cloudflare/lock-rules.ts", "../src/cloudflare/mesh-node.ts", "../src/cloudflare/mesh-node-api.ts", "../src/cloudflare/mesh-node-form.ts", "../src/cloudflare/mesh-node-lifecycle.ts", "../src/cloudflare/mesh-node-token.ts", "../src/cloudflare/providers.ts", "../src/cloudflare/website.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { Unowned } from 'alchemy/AdoptPolicy';\nimport * as Provider from 'alchemy/Provider';\nimport { Resource, type ResourceClass } from 'alchemy/Resource';\n/**\n * `Cloudflare.R2BucketLock` — the lock rule set on one R2 bucket, declared rather than applied by\n * hand. A bucket lock is a RETENTION FLOOR: while a rule covers an object, no API call, no\n * lifecycle rule and no credential can delete it.\n *\n * 🔴 WHY THIS EXISTS AT ALL, AND WHAT IT REPLACES. a consuming stack shipped the retention floor as a\n * documented `wrangler r2 bucket lock add …` step in the runbook, on the measured ground that\n * `alchemy@2.0.0-beta.77` has no lock property anywhere in its R2 namespace. That measurement is\n * still true and it was the wrong conclusion: a step a human runs once is a step an Alchemy plan\n * can never show missing, so removing the floor by hand leaves that stack, its plan and\n * every gate completely green. The operator's rule (2026-09-15) is to cover such a gap with a\n * custom resource over the vendor's SDK, which is what this is.\n *\n * ★ OVER `@distilled.cloud/cloudflare/r2`, THE SAME SDK `Cloudflare.MeshNode` USES\n * (mesh-node-api.ts), NOT THE `cloudflare` NPM SDK THIS RESOURCE USED TO CALL. Measured\n * 2026-09-23 in distilled `1.0.0-rc.12` (the version alchemy@2.0.0-beta.79 pins),\n * `packages/cloudflare/src/services/r2.ts`: `getBucketLock` / `putBucketLock` cover the same\n * `GET`/`PUT /accounts/{account_id}/r2/buckets/{bucket_name}/lock` route the old SDK's\n * `r2.buckets.locks.get`/`.update` did — same `rules[]` body, the `cf-r2-jurisdiction` header\n * spelled as the `jurisdiction` field — but typed as `NoSuchBucket | InvalidRoute |\n * CloudflareRateLimited | CloudflareError` instead of an opaque HTTP status, so the \"bucket\n * does not exist yet\" case below is `catchTag('NoSuchBucket', …)`, never a status check. This\n * is also the swap that lets `client.ts` (the hand-rolled `cloudflare@4.5.0` wrapper) go away:\n * nothing else in the kit imported it.\n *\n * ⚠️ THE RULE SET IS A REPLACE, NOT A MERGE. `PUT` takes the WHOLE list, exactly like R2's\n * lifecycle rules — which is the trap a consuming stack records for\n * `homeflare-git`. Declaring this resource on a bucket whose live rules nobody has read would\n * drop them, so `read` fetches them first and `reconcile` refuses to write when they already\n * match.\n */\nimport type { CloudflareOpContext } from '@distilled.cloud/cloudflare/r2';\nimport { Credentials } from '@distilled.cloud/cloudflare/Credentials';\nimport * as r2 from '@distilled.cloud/cloudflare/r2';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/unstable/http/HttpClient';\nimport {\n type Jurisdiction,\n type R2LockRule,\n jurisdictionOf,\n rulesEqual,\n toBody,\n} from './lock-rules.ts';\nimport type { Providers } from './providers.ts';\n\nexport interface R2BucketLockProps {\n readonly accountId: string;\n readonly bucketName: string;\n /** ⚠️ Part of the bucket's IDENTITY, not a preference — a bucket in another jurisdiction is another bucket. */\n readonly jurisdiction?: Jurisdiction;\n /**\n * ⛔ REQUIRED, AND ITS EMPTY VALUE IS THE DANGEROUS ONE. `rules: []` means NO FLOOR: it is what\n * `delete` sends to take a lock off deliberately. An optional property would let a declaration\n * that simply forgot it send `[]` and silently unlock the repository, reporting success — the\n * same reasoning `LiteLLM.McpServer.allowedTools` is required for.\n */\n readonly rules: readonly R2LockRule[];\n}\n\nexport type R2BucketLockAttributes = {\n readonly bucketName: string;\n readonly jurisdiction: Jurisdiction;\n readonly rules: readonly R2LockRule[];\n};\n\nexport interface R2BucketLock extends Resource<\n 'Cloudflare.R2BucketLock',\n R2BucketLockProps,\n R2BucketLockAttributes,\n never,\n Providers\n> {}\n\n// ⚠️ EXPLICIT ANNOTATION, REQUIRED BY isolatedDeclarations. This file was internal to a\n// monorepo before it was published; a published package emits its .d.ts from a separate\n// tsc pass, so every exported symbol must state its type rather than infer it.\nexport const R2BucketLock: ResourceClass<R2BucketLock> = Resource<R2BucketLock>(\n 'Cloudflare.R2BucketLock',\n {\n /**\n * ⛔ RETAIN, AND ON THIS RESOURCE IT IS NOT THE ESTATE'S HABIT BUT THE WHOLE POINT. A lock is a\n * safety floor: removing the declaration must not remove the floor, because the state it\n * protects is the only physical backup of the estate's one Postgres. `delete` below is\n * implemented — a provider that cannot delete cannot be tested or corrected — and it is\n * reachable only by an operator running the CLI directly, past a deploy wrapper.\n */\n defaultRemovalPolicy: 'retain',\n },\n);\n\n/**\n * 🔴 A 404 HERE IS \"NOTHING TO ADOPT\", AND THE FIRST PLAN PROVED IT IS THE ORDINARY CASE.\n * Measured 2026-09-15, an alchemy plan --detailed on a bucket that does not\n * exist yet: `404 {\"success\":false,\"errors\":[{\"code\":10006,\"message\":\"The specified bucket does\n * not exist.\"}]}` — raised from `read`, during PLANNING, before anything is created. Alchemy\n * calls `read` for a resource with no prior state, so on every first deploy the lock is asked\n * about a bucket the same plan is about to create. Code 10006 is exactly distilled's\n * `NoSuchBucket` tag (r2.ts's error matcher, `[{ code: 10006 }]`), so `catchTag` on it is the\n * same case the status check used to cover — but by the vendor's own error identity, not by\n * reading a number off the response. Letting it propagate would make the resource impossible to\n * plan; swallowing every failure would also hide a 403 from a mis-scoped token, which is the\n * failure this estate spends the most time on. So: `NoSuchBucket` → absent, everything else dies.\n *\n * ⛔ AN EMPTY LIVE RULE SET IS \"NO LOCK\", NOT \"A LOCK WITH NOTHING IN IT\", so it reads as absent\n * and the resource CREATES. The API answers `{}` for a bucket that has never been locked and\n * `{ rules: [] }` for one whose rules were removed; both mean the floor is gone.\n * ⚠️ `Unowned` UNTIL THIS STACK HAS WRITTEN IT. A lock someone applied by hand — which is exactly\n * what the retired runbook step did — must not be silently rewritten by a mistyped declaration;\n * the planner refuses until the resource is piped through `adopt(true)`, which is one line an\n * operator reads in the diff. An adopted rule set that already MATCHES then costs no request at\n * all, because `reconcile` below returns before writing.\n */\nexport const readLock = (\n props: { accountId: string; bucketName: string; jurisdiction?: Jurisdiction },\n written: boolean,\n): Effect.Effect<R2BucketLockAttributes | undefined, never, CloudflareOpContext> =>\n Effect.gen(function* () {\n const jurisdiction = jurisdictionOf(props);\n const live = yield* r2\n .getBucketLock({ accountId: props.accountId, bucketName: props.bucketName, jurisdiction })\n .pipe(\n Effect.catchTag('NoSuchBucket', () => Effect.succeed(undefined)),\n Effect.orDie,\n );\n if (live === undefined) return undefined;\n const rules = (live.rules ?? []) as readonly R2LockRule[];\n if (rules.length === 0) return undefined;\n const attributes: R2BucketLockAttributes = {\n bucketName: props.bucketName,\n jurisdiction,\n rules,\n };\n return written ? attributes : Unowned(attributes);\n });\n\n/**\n * ⛔ A NO-OP MAKES NO REQUEST, AND ON A LOCK THAT MATTERS MORE THAN TIDINESS. `PUT` replaces the\n * rule set; re-sending an identical one on every deploy is a write against the only thing\n * standing between this repository and a delete, for no change. `output` is what the last deploy\n * persisted (or what `read` just adopted), so the comparison costs nothing either.\n * ⛔ `NoSuchBucket` IS NOT CAUGHT HERE. Unlike `read`, a `reconcile` that hits it means the bucket\n * this declaration names is genuinely gone — that is a real failure to surface, not a case to\n * paper over, so it dies like every other tagged error `putBucketLock` can raise.\n */\nexport const reconcileLock = (\n news: R2BucketLockProps,\n output: R2BucketLockAttributes | undefined,\n): Effect.Effect<R2BucketLockAttributes, never, CloudflareOpContext> =>\n Effect.gen(function* () {\n const jurisdiction = jurisdictionOf(news);\n if (output !== undefined && rulesEqual(output.rules, news.rules)) return output;\n yield* r2\n .putBucketLock({\n accountId: news.accountId,\n bucketName: news.bucketName,\n jurisdiction,\n ...toBody(news.rules),\n })\n .pipe(Effect.orDie);\n return { bucketName: news.bucketName, jurisdiction, rules: news.rules };\n });\n\n/**\n * ⛔ DELETING THIS RESOURCE MEANS PUTTING AN EMPTY RULE SET, WHICH IS UNLOCKING THE BUCKET. It is\n * implemented because the retirement path is real — R2 refuses to empty a bucket while any lock\n * rule is configured, so retiring the repository has to start here — and it is behind\n * `defaultRemovalPolicy: 'retain'` and the estate CLI's refusal of `destroy` precisely because\n * no ordinary deploy should ever reach it.\n */\nexport const deleteLock = (\n output: R2BucketLockAttributes,\n accountId: string,\n): Effect.Effect<void, never, CloudflareOpContext> =>\n Effect.gen(function* () {\n yield* r2\n .putBucketLock({\n accountId,\n bucketName: output.bucketName,\n jurisdiction: output.jurisdiction,\n rules: [],\n })\n .pipe(Effect.orDie);\n });\n\nexport const R2BucketLockProvider = () =>\n Provider.effect(\n R2BucketLock,\n Effect.gen(function* () {\n // ★ CAPTURED AT BUILD, LIKE `MeshNodeProvider`. `Credentials` and `HttpClient.HttpClient`\n // are the whole of distilled's `CloudflareOpContext` (r2.ts re-exports the type); pinning\n // them here rather than reading ambient context inside each handler keeps this provider\n // correct whether or not the stack also merges `Cloudflare.providers()`.\n const services = Context.make(Credentials, yield* Credentials).pipe(\n Context.add(HttpClient.HttpClient, yield* HttpClient.HttpClient),\n );\n const run = <A, E>(effect: Effect.Effect<A, E, CloudflareOpContext>) =>\n Effect.provideContext(effect, services);\n\n return R2BucketLock.Provider.of({\n /**\n * ⛔ EMPTY, AND ALCHEMY'S OWN CONTRACT ASKS FOR EXACTLY THAT. `ProviderService.list`:\n * \"Resources with no native enumeration API (… sub-resources keyed entirely by a parent)\n * should return an empty array rather than throwing.\" There is no list-locks endpoint —\n * a lock is reachable only through the bucket that owns it — so enumerating would mean\n * listing every bucket in the account and GETting each one's lock.\n * ⛔⛔ AND `nuke.singleton` IS WHY THAT IS NOT MERELY UNAVAILABLE BUT UNWANTED. `list`\n * feeds `alchemy unsafe nuke`, which lists and then deletes; `delete` here is an UNLOCK.\n * A working enumeration would hand one command the ability to strip the retention floor\n * off every bucket in the account — the precise event a floor exists to make impossible.\n * `singleton` is the documented word for it: always-present configuration whose delete\n * resets rather than removes.\n */\n list: () => Effect.succeed([]),\n nuke: { singleton: true },\n read: Effect.fn(function* ({ olds, output }) {\n const props = olds ?? undefined;\n if (props === undefined) return undefined;\n return yield* run(readLock(props, output !== undefined));\n }),\n reconcile: Effect.fn(({ news, output }) => run(reconcileLock(news, output))),\n delete: Effect.fn(({ olds, output }) => run(deleteLock(output, olds.accountId))),\n });\n }),\n );\n",
|
|
5
|
+
"import { Unowned } from 'alchemy/AdoptPolicy';\nimport * as Provider from 'alchemy/Provider';\nimport { Resource, type ResourceClass } from 'alchemy/Resource';\n/**\n * `Cloudflare.R2BucketLock` — the lock rule set on one R2 bucket, declared rather than applied by\n * hand. A bucket lock is a RETENTION FLOOR: while a rule covers an object, no API call, no\n * lifecycle rule and no credential can delete it.\n *\n * 🔴 WHY THIS EXISTS AT ALL, AND WHAT IT REPLACES. a consuming stack shipped the retention floor as a\n * documented `wrangler r2 bucket lock add …` step in the runbook, on the measured ground that\n * `alchemy@2.0.0-beta.77` has no lock property anywhere in its R2 namespace. That measurement is\n * still true and it was the wrong conclusion: a step a human runs once is a step an Alchemy plan\n * can never show missing, so removing the floor by hand leaves that stack, its plan and\n * every gate completely green. The operator's rule (2026-09-15) is to cover such a gap with a\n * custom resource over the vendor's SDK, which is what this is.\n *\n * ★ OVER `@distilled.cloud/cloudflare/r2`, THE SAME SDK `Cloudflare.MeshNode` USES\n * (mesh-node-api.ts), NOT THE `cloudflare` NPM SDK THIS RESOURCE USED TO CALL. Measured\n * 2026-09-23 in distilled `1.0.0-rc.12` (the version alchemy@2.0.0-beta.79 pins),\n * `packages/cloudflare/src/services/r2.ts`: `getBucketLock` / `putBucketLock` cover the same\n * `GET`/`PUT /accounts/{account_id}/r2/buckets/{bucket_name}/lock` route the old SDK's\n * `r2.buckets.locks.get`/`.update` did — same `rules[]` body, the `cf-r2-jurisdiction` header\n * spelled as the `jurisdiction` field — but typed as `NoSuchBucket | InvalidRoute |\n * CloudflareRateLimited | CloudflareError` instead of an opaque HTTP status, so the \"bucket\n * does not exist yet\" case below is `catchTag('NoSuchBucket', …)`, never a status check. This\n * is also the swap that lets `client.ts` (the hand-rolled `cloudflare@4.5.0` wrapper) go away:\n * nothing else in the kit imported it.\n *\n * ⚠️ THE RULE SET IS A REPLACE, NOT A MERGE. `PUT` takes the WHOLE list, exactly like R2's\n * lifecycle rules — which is the trap a consuming stack records for\n * `homeflare-git`. Declaring this resource on a bucket whose live rules nobody has read would\n * drop them, so `read` fetches them first and `reconcile` refuses to write when they already\n * match.\n */\nimport type { CloudflareOpContext } from '@distilled.cloud/cloudflare/r2';\nimport { Credentials } from '@distilled.cloud/cloudflare/Credentials';\nimport * as r2 from '@distilled.cloud/cloudflare/r2';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/unstable/http/HttpClient';\nimport {\n type Jurisdiction,\n type R2LockRule,\n jurisdictionOf,\n rulesEqual,\n toBody,\n} from './lock-rules.ts';\nimport type { Providers } from './providers.ts';\n\nexport interface R2BucketLockProps {\n readonly accountId: string;\n readonly bucketName: string;\n /** ⚠️ Part of the bucket's IDENTITY, not a preference — a bucket in another jurisdiction is another bucket. */\n readonly jurisdiction?: Jurisdiction;\n /**\n * ⛔ REQUIRED, AND ITS EMPTY VALUE IS THE DANGEROUS ONE. `rules: []` means NO FLOOR: it is what\n * `delete` sends to take a lock off deliberately. An optional property would let a declaration\n * that simply forgot it send `[]` and silently unlock the repository, reporting success — the\n * same reasoning `LiteLLM.McpServer.allowedTools` is required for.\n */\n readonly rules: readonly R2LockRule[];\n}\n\nexport type R2BucketLockAttributes = {\n readonly bucketName: string;\n readonly jurisdiction: Jurisdiction;\n readonly rules: readonly R2LockRule[];\n};\n\nexport interface R2BucketLock extends Resource<\n 'Cloudflare.R2BucketLock',\n R2BucketLockProps,\n R2BucketLockAttributes,\n never,\n Providers\n> {}\n\n// ⚠️ EXPLICIT ANNOTATION, REQUIRED BY isolatedDeclarations. This file was internal to a\n// monorepo before it was published; a published package emits its .d.ts from a separate\n// tsc pass, so every exported symbol must state its type rather than infer it.\nexport const R2BucketLock: ResourceClass<R2BucketLock> = Resource<R2BucketLock>(\n 'Cloudflare.R2BucketLock',\n {\n /**\n * ⛔ RETAIN, AND ON THIS RESOURCE IT IS NOT THE ESTATE'S HABIT BUT THE WHOLE POINT. A lock is a\n * safety floor: removing the declaration must not remove the floor, because the state it\n * protects is the only physical backup of the estate's one Postgres. `delete` below is\n * implemented — a provider that cannot delete cannot be tested or corrected — and it is\n * reachable only by an operator running the CLI directly, past a deploy wrapper.\n */\n defaultRemovalPolicy: 'retain',\n },\n);\n\n/**\n * 🔴 A 404 HERE IS \"NOTHING TO ADOPT\", AND THE FIRST PLAN PROVED IT IS THE ORDINARY CASE.\n * Measured 2026-09-15, an alchemy plan --detailed on a bucket that does not\n * exist yet: `404 {\"success\":false,\"errors\":[{\"code\":10006,\"message\":\"The specified bucket does\n * not exist.\"}]}` — raised from `read`, during PLANNING, before anything is created. Alchemy\n * calls `read` for a resource with no prior state, so on every first deploy the lock is asked\n * about a bucket the same plan is about to create. Code 10006 is exactly distilled's\n * `NoSuchBucket` tag (r2.ts's error matcher, `[{ code: 10006 }]`), so `catchTag` on it is the\n * same case the status check used to cover — but by the vendor's own error identity, not by\n * reading a number off the response. Letting it propagate would make the resource impossible to\n * plan; swallowing every failure would also hide a 403 from a mis-scoped token, which is the\n * failure this estate spends the most time on. So: `NoSuchBucket` → absent, everything else\n * propagates with its SDK tag. Upstream `Cloudflare/R2/BucketSippy.ts` at beta.79 uses this\n * same catch-and-propagate shape; a blanket remap would hide those typed identities (S20/S21).\n *\n * ⛔ AN EMPTY LIVE RULE SET IS \"NO LOCK\", NOT \"A LOCK WITH NOTHING IN IT\", so it reads as absent\n * and the resource CREATES. The API answers `{}` for a bucket that has never been locked and\n * `{ rules: [] }` for one whose rules were removed; both mean the floor is gone.\n * ⚠️ `Unowned` UNTIL THIS STACK HAS WRITTEN IT. A lock someone applied by hand — which is exactly\n * what the retired runbook step did — must not be silently rewritten by a mistyped declaration;\n * the planner refuses until the resource is piped through `adopt(true)`, which is one line an\n * operator reads in the diff. An adopted rule set that already MATCHES then costs no request at\n * all, because `reconcile` below returns before writing.\n */\nexport const readLock = (\n props: { accountId: string; bucketName: string; jurisdiction?: Jurisdiction },\n written: boolean,\n): Effect.Effect<\n R2BucketLockAttributes | undefined,\n Exclude<r2.GetBucketLockError, { _tag: 'NoSuchBucket' }>,\n CloudflareOpContext\n> =>\n Effect.gen(function* () {\n const jurisdiction = jurisdictionOf(props);\n const live = yield* r2\n .getBucketLock({ accountId: props.accountId, bucketName: props.bucketName, jurisdiction })\n .pipe(Effect.catchTag('NoSuchBucket', () => Effect.succeed(undefined)));\n if (live === undefined) return undefined;\n const rules = (live.rules ?? []) as readonly R2LockRule[];\n if (rules.length === 0) return undefined;\n const attributes: R2BucketLockAttributes = {\n bucketName: props.bucketName,\n jurisdiction,\n rules,\n };\n return written ? attributes : Unowned(attributes);\n });\n\n/**\n * ⛔ A NO-OP MAKES NO REQUEST, AND ON A LOCK THAT MATTERS MORE THAN TIDINESS. `PUT` replaces the\n * rule set; re-sending an identical one on every deploy is a write against the only thing\n * standing between this repository and a delete, for no change. `output` is what the last deploy\n * persisted (or what `read` just adopted), so the comparison costs nothing either.\n * ⛔ `NoSuchBucket` IS NOT CAUGHT HERE. Unlike `read`, a `reconcile` that hits it means the bucket\n * this declaration names is genuinely gone — that is a real failure to surface, not a case to\n * paper over, so it propagates like every other typed SDK error `putBucketLock` can raise.\n */\nexport const reconcileLock = (\n news: R2BucketLockProps,\n output: R2BucketLockAttributes | undefined,\n): Effect.Effect<R2BucketLockAttributes, r2.PutBucketLockError, CloudflareOpContext> =>\n Effect.gen(function* () {\n const jurisdiction = jurisdictionOf(news);\n if (output !== undefined && rulesEqual(output.rules, news.rules)) return output;\n yield* r2.putBucketLock({\n accountId: news.accountId,\n bucketName: news.bucketName,\n jurisdiction,\n ...toBody(news.rules),\n });\n return { bucketName: news.bucketName, jurisdiction, rules: news.rules };\n });\n\n/**\n * ⛔ DELETING THIS RESOURCE MEANS PUTTING AN EMPTY RULE SET, WHICH IS UNLOCKING THE BUCKET. It is\n * implemented because the retirement path is real — R2 refuses to empty a bucket while any lock\n * rule is configured, so retiring the repository has to start here — and it is behind\n * `defaultRemovalPolicy: 'retain'` and the estate CLI's refusal of `destroy` precisely because\n * no ordinary deploy should ever reach it.\n * ⛔ IDEMPOTENT (S11): a missing bucket has nothing left to unlock. Catch only `NoSuchBucket`;\n * every other SDK error propagates, like upstream `R2/BucketSippy.ts` at beta.79.\n */\nexport const deleteLock = (\n output: R2BucketLockAttributes,\n accountId: string,\n): Effect.Effect<\n void,\n Exclude<r2.PutBucketLockError, { _tag: 'NoSuchBucket' }>,\n CloudflareOpContext\n> =>\n Effect.gen(function* () {\n yield* r2\n .putBucketLock({\n accountId,\n bucketName: output.bucketName,\n jurisdiction: output.jurisdiction,\n rules: [],\n })\n .pipe(Effect.catchTag('NoSuchBucket', () => Effect.void));\n });\n\nexport const R2BucketLockProvider = () =>\n Provider.effect(\n R2BucketLock,\n Effect.gen(function* () {\n // ★ CAPTURED AT BUILD, LIKE `MeshNodeProvider`. `Credentials` and `HttpClient.HttpClient`\n // are the whole of distilled's `CloudflareOpContext` (r2.ts re-exports the type); pinning\n // them here rather than reading ambient context inside each handler keeps this provider\n // correct whether or not the stack also merges `Cloudflare.providers()`.\n const services = Context.make(Credentials, yield* Credentials).pipe(\n Context.add(HttpClient.HttpClient, yield* HttpClient.HttpClient),\n );\n const run = <A, E>(effect: Effect.Effect<A, E, CloudflareOpContext>) =>\n Effect.provideContext(effect, services);\n\n return R2BucketLock.Provider.of({\n /**\n * ⛔ EMPTY, AND ALCHEMY'S OWN CONTRACT ASKS FOR EXACTLY THAT. `ProviderService.list`:\n * \"Resources with no native enumeration API (… sub-resources keyed entirely by a parent)\n * should return an empty array rather than throwing.\" There is no list-locks endpoint —\n * a lock is reachable only through the bucket that owns it — so enumerating would mean\n * listing every bucket in the account and GETting each one's lock.\n * ⛔⛔ AND `nuke.singleton` IS WHY THAT IS NOT MERELY UNAVAILABLE BUT UNWANTED. `list`\n * feeds `alchemy unsafe nuke`, which lists and then deletes; `delete` here is an UNLOCK.\n * A working enumeration would hand one command the ability to strip the retention floor\n * off every bucket in the account — the precise event a floor exists to make impossible.\n * `singleton` is the documented word for it: always-present configuration whose delete\n * resets rather than removes.\n */\n list: () => Effect.succeed([]),\n nuke: { singleton: true },\n read: Effect.fn(function* ({ olds, output }) {\n const props = olds ?? undefined;\n if (props === undefined) return undefined;\n return yield* run(readLock(props, output !== undefined));\n }),\n reconcile: Effect.fn(({ news, output }) => run(reconcileLock(news, output))),\n delete: Effect.fn(({ olds, output }) => run(deleteLock(output, olds.accountId))),\n });\n }),\n );\n",
|
|
6
6
|
"/**\n * The vocabulary of an R2 lock rule, and the comparison that decides whether to write one.\n *\n * ★ ITS OWN MODULE FOR THE REASON `<estate>/litellm/src/equal.ts` IS ONE: the comparison is the\n * riskiest function in the provider and it deserves to be readable and testable without the\n * lifecycle around it. An equality that returned true for everything would make every reconcile\n * a no-op and the resource would silently never write anything — which looks exactly like a\n * converged stack.\n */\n/** Jurisdictions the API accepts, as the SDK declares them. */\nexport type Jurisdiction = 'default' | 'eu' | 'fedramp';\n\n/**\n * One lock rule. ⚠️ `prefix` OMITTED MEANS THE WHOLE BUCKET — the SDK documents an empty prefix as\n * the way to scope a rule to every object, and omitting the key is how that is spelled on the wire.\n */\nexport type R2LockRule = {\n readonly id: string;\n readonly enabled: boolean;\n readonly prefix?: string;\n readonly condition:\n | { readonly type: 'Age'; readonly maxAgeSeconds: number }\n | { readonly type: 'Date'; readonly date: string }\n | { readonly type: 'Indefinite' };\n};\n\n/** ⚠️ `undefined` and `'default'` are the same jurisdiction; normalise so a diff never sees both. */\nexport const jurisdictionOf = (props: { readonly jurisdiction?: Jurisdiction }): Jurisdiction =>\n props.jurisdiction ?? 'default';\n\n/**\n * ⛔ FIELD BY FIELD, IN ORDER, AND NOT `JSON.stringify` OF EITHER SIDE. The API returns rules in\n * its own key order and omits `prefix` where this repo may spell it `''`; a stringify compare\n * would report drift on every plan and PUT an identical body each deploy. Order across the list\n * IS compared, because the rule set is a replace and the list is what gets sent.\n */\nexport function rulesEqual(a: readonly R2LockRule[], b: readonly R2LockRule[]): boolean {\n if (a.length !== b.length) return false;\n return a.every((left, index) => {\n const right = b[index];\n if (right === undefined) return false;\n if (left.id !== right.id || left.enabled !== right.enabled) return false;\n if ((left.prefix ?? '') !== (right.prefix ?? '')) return false;\n const [lc, rc] = [left.condition, right.condition];\n if (lc.type !== rc.type) return false;\n if (lc.type === 'Age') return rc.type === 'Age' && lc.maxAgeSeconds === rc.maxAgeSeconds;\n if (lc.type === 'Date') return rc.type === 'Date' && lc.date === rc.date;\n return true;\n });\n}\n\n/**\n * The body the SDK sends. Split out so the test can assert the wire shape against one function.\n *\n * ⚠️ IT TAKES THE RULES, NOT THE PROPS, so this module names nothing from the resource — the\n * comparison and the vocabulary stay readable without the lifecycle around them.\n */\nexport const toBody = (rules: readonly R2LockRule[]): { rules: R2LockRule[] } => ({\n rules: rules.map((rule) => ({ ...rule })),\n});\n",
|
|
7
7
|
"/**\n * `Cloudflare.MeshNode` — a Cloudflare Mesh node (a `warp_connector` object), declared without\n * its token ever touching Alchemy state. Usage and the enrolment step: docs/mesh-node.md.\n *\n * 🔴 WHY THIS EXISTS ALONGSIDE `Cloudflare.Tunnel.WarpConnector`. A Mesh node that fronts a\n * private service needs a node record in the graph, so the Gateway rules and DNS records that\n * name it deploy together. Alchemy beta.79's WarpConnector would put the node token — the\n * credential that lets any Linux host join the account's Mesh as that node — into plaintext\n * state on every read, and it cannot create an HA node. See mesh-node-form.ts.\n *\n * ★ REMOVAL POLICY: `retain` BY DEFAULT — see the ★ on `MeshNode` below, and what it does to an\n * `ha` replace in mesh-node-lifecycle.ts.\n */\nimport { Credentials } from '@distilled.cloud/cloudflare/Credentials';\nimport * as Cloudflare from 'alchemy/Cloudflare';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport { Resource, type ResourceClass } from 'alchemy/Resource';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/unstable/http/HttpClient';\nimport {\n type MeshNodeAttributes,\n type MeshNodeProps,\n diffMeshNode,\n validateMeshNode,\n} from './mesh-node-form.ts';\nimport { deleteMeshNode, readMeshNode, reconcileMeshNode } from './mesh-node-lifecycle.ts';\nimport type { Providers } from './providers.ts';\n\nexport interface MeshNode extends Resource<\n 'Cloudflare.MeshNode',\n MeshNodeProps,\n MeshNodeAttributes,\n never,\n Providers\n> {}\n\n/**\n * ★ `defaultRemovalPolicy: 'retain'`, LIKE EVERY KIT RESOURCE WHOSE DELETION BREAKS ITS CONSUMERS\n * (the `Bao.*` families, `R2BucketLock`, the Proxmox storage families; the reasoning is written\n * once in proxmox/resource.ts). Deleting a node cuts every enrolled replica off the Mesh, and\n * nothing brings it back: a new node has a new id, a new token and a new Mesh IP per replica, so\n * each host must be re-enrolled by hand and every Gateway rule or allow-list that pins the old\n * Mesh IP breaks. So dropping the declaration, or `alchemy destroy`, leaves the node live.\n * ⚠️ IT ALSO SKIPS THE OLD NODE'S DELETE IN A REPLACE (Apply.ts, `deleteOldGenerations` and the\n * GC's `retainOldGeneration`, beta.79). A same-name `ha` change therefore REFUSES, deleting\n * nothing, until that deploy opts in with `.pipe(RemovalPolicy.destroy())`; a create-first\n * replace leaves the old node live and unmanaged. Both measured in mesh-node-policy.test.ts.\n * ⛔ `delete` STAYS FULLY IMPLEMENTED. Retain is Terraform's `prevent_destroy`, not a stub: it runs\n * the moment a declaration opts in with `.pipe(RemovalPolicy.destroy())`.\n */\nexport const MeshNode: ResourceClass<MeshNode> = Resource<MeshNode>('Cloudflare.MeshNode', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** What every call below needs: the account, credentials and HTTP — Alchemy's own trio. */\nexport type MeshNodeServices =\n | Cloudflare.CloudflareEnvironment\n | Credentials\n | HttpClient.HttpClient;\n\n/** The account id, resolved the way every `alchemy/Cloudflare` provider resolves it. */\nconst accountId = Effect.gen(function* () {\n const resolved = yield* yield* Cloudflare.CloudflareEnvironment;\n return resolved.accountId;\n});\n\n/**\n * ★ `Provider.effect`, CAPTURING THE THREE SERVICES AT BUILD. `Provider.succeed` (what Alchemy's\n * own providers use) leaves each handler to find CloudflareEnvironment and Credentials in the\n * engine's context at call time — which works for `Cloudflare.providers()` only because it\n * `provideMerge`s them into the stack. Capturing them here keeps this provider correct whether\n * or not the stack also merges `Cloudflare.providers()`.\n */\nexport const MeshNodeProvider = () =>\n Provider.effect(\n MeshNode,\n Effect.gen(function* () {\n const services = Context.make(\n Cloudflare.CloudflareEnvironment,\n yield* Cloudflare.CloudflareEnvironment,\n ).pipe(\n Context.add(Credentials, yield* Credentials),\n Context.add(HttpClient.HttpClient, yield* HttpClient.HttpClient),\n );\n const run = <A, E>(effect: Effect.Effect<A, E, MeshNodeServices>) =>\n Effect.provideContext(effect, services);\n\n return MeshNode.Provider.of({\n stables: ['id', 'accountId', 'ha'],\n /**\n * ⛔ EMPTY, AND `nuke.skip`. Alchemy's own `Cloudflare.Tunnel.WarpConnector` already lists\n * every `warp_connector` in the account for `alchemy unsafe nuke`; a second listing here\n * would make nuke delete each node twice. `read` does not depend on this.\n */\n list: () => Effect.succeed([]),\n nuke: { skip: true },\n /**\n * ⛔ VALIDATE AT PLAN TIME, NOT ONLY IN `reconcile`. An `ha` replace is delete-first: the\n * engine deletes the old node BEFORE the new generation's reconcile runs, so a\n * declaration refused there would leave no node at all. launchd's job-preflight.ts\n * refuses at plan time for the same reason.\n */\n diff: ({ news, output }) =>\n run(\n Effect.gen(function* () {\n const invalid = isResolved(news) ? validateMeshNode(news) : undefined;\n if (invalid !== undefined) return yield* Effect.fail(invalid);\n return diffMeshNode(news, output, yield* accountId);\n }),\n ),\n read: ({ olds, output }) =>\n run(Effect.flatMap(accountId, (account) => readMeshNode(account, olds, output))),\n reconcile: ({ news, output }) =>\n run(Effect.flatMap(accountId, (account) => reconcileMeshNode(account, news, output))),\n delete: ({ output }) => run(deleteMeshNode(output)),\n });\n }),\n );\n",
|
|
8
8
|
"/**\n * The `warp_connector` calls a Cloudflare Mesh node needs, and nothing else.\n *\n * ★ A MESH NODE IS A `warp_connector` OBJECT. Cloudflare's Mesh docs create one with\n * `POST /accounts/{account_id}/warp_connector` and fetch its enrolment token from\n * `GET …/warp_connector/{id}/token` (developers.cloudflare.com/mesh/get-started, read\n * 2026-09-21). There is no separate \"mesh node\" endpoint.\n *\n * ★ OVER `@distilled.cloud/cloudflare`, THE SDK ALCHEMY'S OWN CLOUDFLARE PROVIDERS USE — and, as\n * of 2026-09-23, the same one `R2BucketLock` calls too (r2-bucket-lock.ts), not the `cloudflare`\n * npm SDK either used before that. Measured 2026-09-21: `cloudflare@4.5.0`'s\n * `WARPConnectorCreateParams` has only `account_id` and `name`, so it cannot create an HA node.\n * distilled `1.0.0-rc.12` (the version alchemy@2.0.0-beta.79 pins) has `ha?: boolean` on\n * `CreateTunnelWarpConnectorRequest`, typed errors (`TunnelNotFound` code 1002 / 404,\n * `DuplicateTunnelName` code 1013), and resolves credentials and the account exactly the way\n * `Cloudflare.Tunnel.WarpConnector` and `Cloudflare.Gateway.Rule` do — so the node and the Gateway\n * rules that pin its Mesh IP always land in the same account.\n *\n * ⛔ NO FUNCTION IN THIS FILE READS THE NODE TOKEN, and `observe` copies named fields only. The\n * HA docs say the create response carries a `token` field; distilled's decoder copies only the\n * fields in its schema (protocol.ts, `getProps(outputAst)`), and `observe` below would drop it\n * again if it ever got through. The one token read lives in mesh-node-token.ts, on demand.\n */\nimport * as zeroTrust from '@distilled.cloud/cloudflare/zero-trust';\nimport * as Data from 'effect/Data';\nimport * as Effect from 'effect/Effect';\nimport * as Stream from 'effect/Stream';\n\n/** `inactive` (never run), `degraded`, `healthy` or `down` — Cloudflare's own four. */\nexport type MeshNodeStatus = 'inactive' | 'degraded' | 'healthy' | 'down';\n\n/** A live node as this package sees it. ⛔ There is no token field here, on purpose. */\nexport interface ObservedNode {\n readonly id: string;\n readonly name: string;\n readonly status: MeshNodeStatus | undefined;\n}\n\n/** A refusal or failure, carrying the sentence an operator needs. Never a token. */\nexport class MeshNodeError extends Data.TaggedError('MeshNodeError')<{\n readonly message: string;\n}> {}\n\ntype Raw = {\n readonly id?: string | null;\n readonly name?: string | null;\n readonly status?: string | null;\n readonly deletedAt?: string | null;\n};\n\nconst STATUSES: readonly string[] = ['inactive', 'degraded', 'healthy', 'down'];\n\n/**\n * ⚠️ A DELETED NODE IS NOT A NODE. Cloudflare keeps deleted tunnels (every response carries\n * `deleted_at`, and the list takes `is_deleted`), so a `GET` by id can answer for one. Treating\n * that as live would \"adopt\" a tombstone and PATCH it.\n */\nexport const observe = (raw: Raw): ObservedNode | undefined => {\n if (typeof raw.id !== 'string' || raw.id.length === 0) return undefined;\n if (raw.deletedAt !== undefined && raw.deletedAt !== null) return undefined;\n const status =\n typeof raw.status === 'string' && STATUSES.includes(raw.status)\n ? (raw.status as MeshNodeStatus)\n : undefined;\n return { id: raw.id, name: raw.name ?? '', status };\n};\n\n/** The node with this id, or `undefined` when it is gone (404 / code 1002, or soft-deleted). */\nexport const getNode = (accountId: string, nodeId: string) =>\n zeroTrust.getTunnelWarpConnector({ accountId, tunnelId: nodeId }).pipe(\n Effect.map(observe),\n Effect.catchTag('TunnelNotFound', () => Effect.succeed(undefined)),\n );\n\n/**\n * The live node with exactly this name, or `undefined`.\n *\n * ★ `name` is also sent as the list filter, but the match is re-checked here: the filter's\n * exactness is not documented, and a prefix match would adopt the wrong node.\n * ⛔ Two live matches is refused rather than resolved. Names are unique per account (the create\n * answers code 1013 otherwise), so two means something this package does not understand.\n */\nexport const findNodeByName = (accountId: string, name: string) =>\n zeroTrust.listTunnelWarpConnectors.items({ accountId, name, isDeleted: false }).pipe(\n Stream.map(observe),\n Stream.filter((node): node is ObservedNode => node !== undefined && node.name === name),\n Stream.runCollect,\n Effect.flatMap((chunk) => {\n const matches = Array.from(chunk);\n if (matches.length <= 1) return Effect.succeed(matches[0]);\n const ids = matches.map((node) => node.id).join(', ');\n return Effect.fail(\n new MeshNodeError({\n message: `Mesh node name \"${name}\" matches ${matches.length} live nodes (${ids}). Names are unique per account, so refusing to guess which one is meant.`,\n }),\n );\n }),\n );\n\n/**\n * ⛔ `ha` IS SENT ON CREATE AND NOWHERE ELSE. Cloudflare's HA page: \"High availability is set at\n * node creation time and cannot be changed afterward.\" The PATCH body (`PatchTunnelWarpConnector\n * Request`) has only `name` and `tunnelSecret`.\n */\nexport const createNode = (accountId: string, name: string, ha: boolean) =>\n zeroTrust.createTunnelWarpConnector({ accountId, name, ha }).pipe(\n Effect.flatMap((raw) => {\n const node = observe(raw);\n return node === undefined\n ? Effect.fail(\n new MeshNodeError({ message: `Creating Mesh node \"${name}\" returned no id.` }),\n )\n : Effect.succeed(node);\n }),\n );\n\n/** ★ A rename is a PATCH: same id, same token, same enrolled replicas and Mesh IP. */\nexport const renameNode = (accountId: string, nodeId: string, name: string) =>\n zeroTrust\n .patchTunnelWarpConnector({ accountId, tunnelId: nodeId, name })\n .pipe(Effect.map((raw) => observe(raw) ?? { id: nodeId, name, status: undefined }));\n\n/** Idempotent: a node already gone (404 / code 1002) is a successful delete. */\nexport const deleteNode = (accountId: string, nodeId: string) =>\n zeroTrust.deleteTunnelWarpConnector({ accountId, tunnelId: nodeId }).pipe(\n Effect.asVoid,\n Effect.catchTag('TunnelNotFound', () => Effect.void),\n );\n",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"/**\n * The HomeFlare Cloudflare provider collection, in the shape `LiteLLM.providers()` has.\n *\n * ⚠️ THIS IS NOT `alchemy/Cloudflare`'s COLLECTION AND DOES NOT REPLACE IT. A stack that declares\n * both a `Cloudflare.R2.Bucket` and this lock merges the two:\n * `Layer.mergeAll(Cloudflare.providers(), HomeflareCloudflare.providers())` — the shape\n * a consuming stack names for one talking to more than one account.\n *\n * ★ ONE CREDENTIAL PATH NOW, NOT TWO. Until 2026-09-23 `R2BucketLock` ran over the `cloudflare`\n * npm SDK with its own `CLOUDFLARE_API_TOKEN` read (`client.ts`, since deleted) while `MeshNode`\n * ran over `@distilled.cloud/cloudflare` through `Cloudflare.CloudflareApiLive()`. Both\n * providers now call distilled, so both resolve credentials and the account the same way\n * `Cloudflare.providers()` does (an Alchemy profile, or `CLOUDFLARE_API_TOKEN` +\n * `CLOUDFLARE_ACCOUNT_ID` in CI) — a lock and the Gateway rules that reference the same bucket\n * land in the same account.\n * ⚠️ THE LAYER IS BUILT TWICE ON PURPOSE, once per provider, even when the stack also merges\n * `Cloudflare.providers()`. `Layer.provide`, not `provideMerge`: each feeds its own provider\n * only and adds nothing to the stack's context.\n */\nimport * as Cloudflare from 'alchemy/Cloudflare';\nimport * as Provider from 'alchemy/Provider';\nimport * as Layer from 'effect/Layer';\nimport { MeshNode, MeshNodeProvider } from './mesh-node.ts';\nimport { R2BucketLock, R2BucketLockProvider } from './r2-bucket-lock.ts';\n\nexport class Providers extends Provider.ProviderCollection<Providers>()('HomeflareCloudflare') {}\n\n// ⛔ `orDie` ON BOTH, as `Cloudflare.providers()` ends with: a stack's providers layer must not\n// fail, and a profile that cannot resolve is a defect carrying Alchemy's own sentence.\nexport const providers = () =>\n Layer.effect(Providers, Provider.collection([R2BucketLock, MeshNode])).pipe(\n Layer.provide(\n Layer.mergeAll(\n R2BucketLockProvider().pipe(Layer.provide(Cloudflare.CloudflareApiLive()), Layer.orDie),\n MeshNodeProvider().pipe(Layer.provide(Cloudflare.CloudflareApiLive()), Layer.orDie),\n ),\n ),\n );\n",
|
|
13
13
|
"/**\n * House defaults on Alchemy's Website stacks — Astro and Vite, which is what we ship.\n *\n * ★ NOT Nextjs. The blog measured Website.Nextjs planning as **create** because it\n * hashes source; adopt is `Worker`, not Nextjs. Do not add a Nextjs helper until an\n * app actually deploys that way.\n *\n * ⛔ `disable_nodejs_process_v2` ON ASTRO IS LOAD-BEARING. Workerd process-v2 (compat\n * date 2025-09-15) makes every Astro page return `[object Object]`. Vite/TanStack\n * Start does not need that flag; it needs `nodejs_compat` (Alchemy already defaults\n * it on Vite).\n *\n * ⛔ Alchemy injects `@alchemy.run/frontend-frameworks/astro`. Do not add\n * `@astrojs/cloudflare` — that is the wrangler path.\n *\n * ★ Alchemy's Website props are an Effect-wrapped InputProps union. We do not re-export\n * that type — isolatedDeclarations cannot name it. Extra Alchemy fields still pass\n * through via the rest bag; the assertion is only at the call into Alchemy.\n */\nimport * as AdoptPolicy from 'alchemy/AdoptPolicy';\nimport * as Cloudflare from 'alchemy/Cloudflare';\nimport * as RemovalPolicy from 'alchemy/RemovalPolicy';\n\nconst ASTRO_FLAGS: readonly string[] = ['nodejs_compat', 'disable_nodejs_process_v2'];\n\nexport interface AstroWebsiteProps {\n readonly rootDir?: string;\n readonly name?: string;\n readonly sessionKVBindingName?: string | false;\n readonly compatibility?: { readonly flags?: readonly string[]; readonly date?: string };\n}\n\nexport interface ViteWebsiteProps {\n readonly rootDir?: string;\n readonly name?: string;\n}\n\n/**\n * `Cloudflare.Website.Astro` with house flags, no auto session KV, adopt+retain.\n *\n * const site = yield* astroWebsite('subnetcalc', { rootDir });\n */\nexport function astroWebsite(\n name: string,\n props: AstroWebsiteProps,\n): ReturnType<typeof Cloudflare.Website.Astro> {\n const flags = props.compatibility?.flags ?? ASTRO_FLAGS;\n const merged = {\n ...props,\n name: props.name ?? name,\n sessionKVBindingName: props.sessionKVBindingName ?? false,\n compatibility: { ...props.compatibility, flags: [...flags] },\n };\n return Cloudflare.Website.Astro(name, merged as never).pipe(\n AdoptPolicy.adopt(true),\n RemovalPolicy.retain(),\n );\n}\n\n/**\n * `Cloudflare.Website.Vite` — TanStack Start, SolidStart, static Vite.\n * `nodejs_compat` is Alchemy's Vite default; we do not add process-v2 here.\n *\n * const app = yield* viteWebsite('aimto', { rootDir: webRoot });\n */\nexport function viteWebsite(\n name: string,\n props?: ViteWebsiteProps,\n): ReturnType<typeof Cloudflare.Website.Vite> {\n const merged = { ...props, name: props?.name ?? name };\n return Cloudflare.Website.Vite(name, merged as never).pipe(\n AdoptPolicy.adopt(true),\n RemovalPolicy.retain(),\n );\n}\n"
|
|
14
14
|
],
|
|
15
|
-
"mappings": ";AAAA;AACA;AACA;AAiCA;AACA;AACA;AACA;AACA;;;ACZO,IAAM,iBAAiB,CAAC,UAC7B,MAAM,gBAAgB;AAQjB,SAAS,UAAU,CAAC,GAA0B,GAAmC;AAAA,EACtF,IAAI,EAAE,WAAW,EAAE;AAAA,IAAQ,OAAO;AAAA,EAClC,OAAO,EAAE,MAAM,CAAC,MAAM,UAAU;AAAA,IAC9B,MAAM,QAAQ,EAAE;AAAA,IAChB,IAAI,UAAU;AAAA,MAAW,OAAO;AAAA,IAChC,IAAI,KAAK,OAAO,MAAM,MAAM,KAAK,YAAY,MAAM;AAAA,MAAS,OAAO;AAAA,IACnE,KAAK,KAAK,UAAU,SAAS,MAAM,UAAU;AAAA,MAAK,OAAO;AAAA,IACzD,OAAO,IAAI,MAAM,CAAC,KAAK,WAAW,MAAM,SAAS;AAAA,IACjD,IAAI,GAAG,SAAS,GAAG;AAAA,MAAM,OAAO;AAAA,IAChC,IAAI,GAAG,SAAS;AAAA,MAAO,OAAO,GAAG,SAAS,SAAS,GAAG,kBAAkB,GAAG;AAAA,IAC3E,IAAI,GAAG,SAAS;AAAA,MAAQ,OAAO,GAAG,SAAS,UAAU,GAAG,SAAS,GAAG;AAAA,IACpE,OAAO;AAAA,GACR;AAAA;AASI,IAAM,SAAS,CAAC,WAA2D;AAAA,EAChF,OAAO,MAAM,IAAI,CAAC,UAAU,KAAK,KAAK,EAAE;AAC1C;;;ADqBO,IAAM,eAA4C,SACvD,2BACA;AAAA,EAQE,sBAAsB;AACxB,CACF;
|
|
16
|
-
"debugId": "
|
|
15
|
+
"mappings": "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",
|
|
16
|
+
"debugId": "7CF2B122E4A4953564756E2164756E21",
|
|
17
17
|
"names": []
|
|
18
18
|
}
|
|
@@ -33,6 +33,7 @@ import { Resource, type ResourceClass } from 'alchemy/Resource';
|
|
|
33
33
|
*/
|
|
34
34
|
import type { CloudflareOpContext } from '@distilled.cloud/cloudflare/r2';
|
|
35
35
|
import { Credentials } from '@distilled.cloud/cloudflare/Credentials';
|
|
36
|
+
import * as r2 from '@distilled.cloud/cloudflare/r2';
|
|
36
37
|
import * as Effect from 'effect/Effect';
|
|
37
38
|
import * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
38
39
|
import { type Jurisdiction, type R2LockRule } from './lock-rules.ts';
|
|
@@ -69,7 +70,9 @@ export declare const R2BucketLock: ResourceClass<R2BucketLock>;
|
|
|
69
70
|
* same case the status check used to cover — but by the vendor's own error identity, not by
|
|
70
71
|
* reading a number off the response. Letting it propagate would make the resource impossible to
|
|
71
72
|
* plan; swallowing every failure would also hide a 403 from a mis-scoped token, which is the
|
|
72
|
-
* failure this estate spends the most time on. So: `NoSuchBucket` → absent, everything else
|
|
73
|
+
* failure this estate spends the most time on. So: `NoSuchBucket` → absent, everything else
|
|
74
|
+
* propagates with its SDK tag. Upstream `Cloudflare/R2/BucketSippy.ts` at beta.79 uses this
|
|
75
|
+
* same catch-and-propagate shape; a blanket remap would hide those typed identities (S20/S21).
|
|
73
76
|
*
|
|
74
77
|
* ⛔ AN EMPTY LIVE RULE SET IS "NO LOCK", NOT "A LOCK WITH NOTHING IN IT", so it reads as absent
|
|
75
78
|
* and the resource CREATES. The API answers `{}` for a bucket that has never been locked and
|
|
@@ -84,7 +87,9 @@ export declare const readLock: (props: {
|
|
|
84
87
|
accountId: string;
|
|
85
88
|
bucketName: string;
|
|
86
89
|
jurisdiction?: Jurisdiction;
|
|
87
|
-
}, written: boolean) => Effect.Effect<R2BucketLockAttributes | undefined,
|
|
90
|
+
}, written: boolean) => Effect.Effect<R2BucketLockAttributes | undefined, Exclude<r2.GetBucketLockError, {
|
|
91
|
+
_tag: 'NoSuchBucket';
|
|
92
|
+
}>, CloudflareOpContext>;
|
|
88
93
|
/**
|
|
89
94
|
* ⛔ A NO-OP MAKES NO REQUEST, AND ON A LOCK THAT MATTERS MORE THAN TIDINESS. `PUT` replaces the
|
|
90
95
|
* rule set; re-sending an identical one on every deploy is a write against the only thing
|
|
@@ -92,16 +97,20 @@ export declare const readLock: (props: {
|
|
|
92
97
|
* persisted (or what `read` just adopted), so the comparison costs nothing either.
|
|
93
98
|
* ⛔ `NoSuchBucket` IS NOT CAUGHT HERE. Unlike `read`, a `reconcile` that hits it means the bucket
|
|
94
99
|
* this declaration names is genuinely gone — that is a real failure to surface, not a case to
|
|
95
|
-
* paper over, so it
|
|
100
|
+
* paper over, so it propagates like every other typed SDK error `putBucketLock` can raise.
|
|
96
101
|
*/
|
|
97
|
-
export declare const reconcileLock: (news: R2BucketLockProps, output: R2BucketLockAttributes | undefined) => Effect.Effect<R2BucketLockAttributes,
|
|
102
|
+
export declare const reconcileLock: (news: R2BucketLockProps, output: R2BucketLockAttributes | undefined) => Effect.Effect<R2BucketLockAttributes, r2.PutBucketLockError, CloudflareOpContext>;
|
|
98
103
|
/**
|
|
99
104
|
* ⛔ DELETING THIS RESOURCE MEANS PUTTING AN EMPTY RULE SET, WHICH IS UNLOCKING THE BUCKET. It is
|
|
100
105
|
* implemented because the retirement path is real — R2 refuses to empty a bucket while any lock
|
|
101
106
|
* rule is configured, so retiring the repository has to start here — and it is behind
|
|
102
107
|
* `defaultRemovalPolicy: 'retain'` and the estate CLI's refusal of `destroy` precisely because
|
|
103
108
|
* no ordinary deploy should ever reach it.
|
|
109
|
+
* ⛔ IDEMPOTENT (S11): a missing bucket has nothing left to unlock. Catch only `NoSuchBucket`;
|
|
110
|
+
* every other SDK error propagates, like upstream `R2/BucketSippy.ts` at beta.79.
|
|
104
111
|
*/
|
|
105
|
-
export declare const deleteLock: (output: R2BucketLockAttributes, accountId: string) => Effect.Effect<void,
|
|
112
|
+
export declare const deleteLock: (output: R2BucketLockAttributes, accountId: string) => Effect.Effect<void, Exclude<r2.PutBucketLockError, {
|
|
113
|
+
_tag: 'NoSuchBucket';
|
|
114
|
+
}>, CloudflareOpContext>;
|
|
106
115
|
export declare const R2BucketLockProvider: () => import("effect/Layer").Layer<Provider.Provider<R2BucketLock>, never, Credentials | HttpClient.HttpClient>;
|
|
107
116
|
//# sourceMappingURL=r2-bucket-lock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2-bucket-lock.d.ts","sourceRoot":"","sources":["../../src/cloudflare/r2-bucket-lock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAChE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"r2-bucket-lock.d.ts","sourceRoot":"","sources":["../../src/cloudflare/r2-bucket-lock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAChE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,UAAU,EAIhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+GAA+G;IAC/G,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CACvC;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CACvC,CAAC;AAEF,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,EACL,SAAS,CACV;CAAG;AAKJ,eAAO,MAAM,YAAY,EAAE,aAAa,CAAC,YAAY,CAYpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,QAAQ,UACZ;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,WACpE,OAAO,KACf,MAAM,CAAC,MAAM,CACd,sBAAsB,GAAG,SAAS,EAClC,OAAO,CAAC,EAAE,CAAC,kBAAkB,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,EACxD,mBAAmB,CAgBjB,CAAC;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,SAClB,iBAAiB,UACf,sBAAsB,GAAG,SAAS,KACzC,MAAM,CAAC,MAAM,CAAC,sBAAsB,EAAE,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,CAW/E,CAAC;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,WACb,sBAAsB,aACnB,MAAM,KAChB,MAAM,CAAC,MAAM,CACd,IAAI,EACJ,OAAO,CAAC,EAAE,CAAC,kBAAkB,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,EACxD,mBAAmB,CAWjB,CAAC;AAEL,eAAO,MAAM,oBAAoB,iHAuC9B,CAAC"}
|
package/dist/grafana/index.d.ts
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
* depend on.
|
|
8
8
|
*
|
|
9
9
|
* `Grafana.Datasource`, `Grafana.Folder`, `Grafana.Dashboard`, `Grafana.ContactPoint`,
|
|
10
|
-
* `Grafana.MuteTiming`, `Grafana.MessageTemplate
|
|
11
|
-
* `Grafana.NotificationPolicy`
|
|
12
|
-
*
|
|
13
|
-
* docs/grafana-
|
|
10
|
+
* `Grafana.MuteTiming`, `Grafana.MessageTemplate`, `Grafana.AlertRuleGroup` and
|
|
11
|
+
* `Grafana.NotificationPolicy` all ship here — see docs/grafana.md, docs/grafana-folder-dashboard.md,
|
|
12
|
+
* docs/grafana-alerting.md, docs/grafana-alerting-rules.md and
|
|
13
|
+
* docs/grafana-notification-policy.md for what shipped.
|
|
14
14
|
*/
|
|
15
15
|
export { type AlertRuleGroupAttributes, type AlertRuleGroupProps, type AlertRuleInput, GrafanaAlertRuleGroup, GrafanaAlertRuleGroupProvider, } from './alert-rule-group.ts';
|
|
16
|
+
export { type NotificationPolicyAttributes, type NotificationPolicyProps, type PolicyRoute, GrafanaNotificationPolicy, GrafanaNotificationPolicyProvider, } from './notification-policy.ts';
|
|
16
17
|
export { type DatasourceAttributes, type DatasourceProps, GrafanaDatasource, GrafanaDatasourceProvider, } from './datasource.ts';
|
|
17
18
|
export { type DashboardAttributes, type DashboardModel, type DashboardProps, GrafanaDashboard, GrafanaDashboardProvider, } from './dashboard.ts';
|
|
18
19
|
export { type FolderAttributes, type FolderProps, GrafanaFolder, GrafanaFolderProvider, GrafanaFolderReparentError, } from './folder.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grafana/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,aAAa,EACb,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,KAAK,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grafana/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,aAAa,EACb,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,KAAK,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|