@homeflare/alchemy 0.48.1 → 0.50.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 +11 -0
- package/dist/cloudflare/cloudflared-tunnel-api.d.ts +87 -0
- package/dist/cloudflare/cloudflared-tunnel-api.d.ts.map +1 -0
- package/dist/cloudflare/cloudflared-tunnel-form.d.ts +49 -0
- package/dist/cloudflare/cloudflared-tunnel-form.d.ts.map +1 -0
- package/dist/cloudflare/cloudflared-tunnel-harness.d.ts +45 -0
- package/dist/cloudflare/cloudflared-tunnel-harness.d.ts.map +1 -0
- package/dist/cloudflare/cloudflared-tunnel-lifecycle.d.ts +21 -0
- package/dist/cloudflare/cloudflared-tunnel-lifecycle.d.ts.map +1 -0
- package/dist/cloudflare/cloudflared-tunnel.d.ts +39 -0
- package/dist/cloudflare/cloudflared-tunnel.d.ts.map +1 -0
- package/dist/cloudflare/fake-access.d.ts +40 -0
- package/dist/cloudflare/fake-access.d.ts.map +1 -0
- package/dist/cloudflare/fake-mesh.d.ts +7 -2
- package/dist/cloudflare/fake-mesh.d.ts.map +1 -1
- package/dist/cloudflare/fake-tunnel.d.ts +48 -0
- package/dist/cloudflare/fake-tunnel.d.ts.map +1 -0
- package/dist/cloudflare/index.d.ts +15 -4
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +518 -7
- package/dist/cloudflare/index.js.map +15 -4
- package/dist/cloudflare/providers.d.ts +1 -1
- package/dist/cloudflare/providers.d.ts.map +1 -1
- package/dist/cloudflare/saas-oidc-api.d.ts +88 -0
- package/dist/cloudflare/saas-oidc-api.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-consumer.d.ts +22 -0
- package/dist/cloudflare/saas-oidc-consumer.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-error.d.ts +22 -0
- package/dist/cloudflare/saas-oidc-error.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-form.d.ts +48 -0
- package/dist/cloudflare/saas-oidc-form.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-harness.d.ts +50 -0
- package/dist/cloudflare/saas-oidc-harness.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-lifecycle.d.ts +14 -0
- package/dist/cloudflare/saas-oidc-lifecycle.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-props.d.ts +139 -0
- package/dist/cloudflare/saas-oidc-props.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-team.d.ts +9 -0
- package/dist/cloudflare/saas-oidc-team.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc-wire.d.ts +58 -0
- package/dist/cloudflare/saas-oidc-wire.d.ts.map +1 -0
- package/dist/cloudflare/saas-oidc.d.ts +36 -0
- package/dist/cloudflare/saas-oidc.d.ts.map +1 -0
- package/dist/kubernetes/helm-chart-bounded.d.ts +44 -0
- package/dist/kubernetes/helm-chart-bounded.d.ts.map +1 -0
- package/dist/kubernetes/index.d.ts +12 -0
- package/dist/kubernetes/index.d.ts.map +1 -0
- package/dist/kubernetes/index.js +585 -0
- package/dist/kubernetes/index.js.map +19 -0
- package/dist/kubernetes/ready-checks.d.ts +45 -0
- package/dist/kubernetes/ready-checks.d.ts.map +1 -0
- package/dist/kubernetes/ready-classify.d.ts +23 -0
- package/dist/kubernetes/ready-classify.d.ts.map +1 -0
- package/dist/kubernetes/ready-connect.d.ts +29 -0
- package/dist/kubernetes/ready-connect.d.ts.map +1 -0
- package/dist/kubernetes/ready-declare.d.ts +5 -0
- package/dist/kubernetes/ready-declare.d.ts.map +1 -0
- package/dist/kubernetes/ready-errors.d.ts +80 -0
- package/dist/kubernetes/ready-errors.d.ts.map +1 -0
- package/dist/kubernetes/ready-poll.d.ts +61 -0
- package/dist/kubernetes/ready-poll.d.ts.map +1 -0
- package/dist/kubernetes/ready.d.ts +74 -0
- package/dist/kubernetes/ready.d.ts.map +1 -0
- package/dist/talos/fake-apiserver.d.ts +11 -2
- package/dist/talos/fake-apiserver.d.ts.map +1 -1
- package/docs/cloudflared-tunnel.md +136 -0
- package/docs/credentials.md +1 -1
- package/docs/kubernetes-ready.md +146 -0
- package/docs/ownership.md +3 -2
- package/docs/peers.md +13 -0
- package/docs/provider-standard.md +7 -0
- package/docs/saas-oidc.md +185 -0
- package/docs/upstream-conformance-families.md +1 -1
- package/docs/upstream-conformance.md +3 -0
- package/package.json +7 -1
- package/src/cloudflare/cloudflared-tunnel-api.ts +150 -0
- package/src/cloudflare/cloudflared-tunnel-edges.test.ts +179 -0
- package/src/cloudflare/cloudflared-tunnel-form.ts +78 -0
- package/src/cloudflare/cloudflared-tunnel-harness.ts +126 -0
- package/src/cloudflare/cloudflared-tunnel-lifecycle.ts +146 -0
- package/src/cloudflare/cloudflared-tunnel-state.test.ts +104 -0
- package/src/cloudflare/cloudflared-tunnel.test.ts +164 -0
- package/src/cloudflare/cloudflared-tunnel.ts +116 -0
- package/src/cloudflare/fake-access.ts +196 -0
- package/src/cloudflare/fake-mesh.ts +6 -3
- package/src/cloudflare/fake-tunnel.ts +148 -0
- package/src/cloudflare/index.ts +27 -4
- package/src/cloudflare/providers.ts +16 -3
- package/src/cloudflare/saas-oidc-api.ts +224 -0
- package/src/cloudflare/saas-oidc-consumer.ts +35 -0
- package/src/cloudflare/saas-oidc-error.ts +52 -0
- package/src/cloudflare/saas-oidc-form.test.ts +227 -0
- package/src/cloudflare/saas-oidc-form.ts +190 -0
- package/src/cloudflare/saas-oidc-harness.ts +140 -0
- package/src/cloudflare/saas-oidc-lifecycle.ts +150 -0
- package/src/cloudflare/saas-oidc-parse-error.test.ts +180 -0
- package/src/cloudflare/saas-oidc-props.ts +147 -0
- package/src/cloudflare/saas-oidc-read.test.ts +85 -0
- package/src/cloudflare/saas-oidc-stable.test.ts +38 -0
- package/src/cloudflare/saas-oidc-state.test.ts +128 -0
- package/src/cloudflare/saas-oidc-team.test.ts +88 -0
- package/src/cloudflare/saas-oidc-team.ts +70 -0
- package/src/cloudflare/saas-oidc-wire.ts +116 -0
- package/src/cloudflare/saas-oidc.test.ts +201 -0
- package/src/cloudflare/saas-oidc.ts +107 -0
- package/src/kubernetes/helm-chart-bounded.test.ts +242 -0
- package/src/kubernetes/helm-chart-bounded.ts +110 -0
- package/src/kubernetes/index.ts +28 -0
- package/src/kubernetes/ready-backoff.test.ts +124 -0
- package/src/kubernetes/ready-checks.test.ts +106 -0
- package/src/kubernetes/ready-checks.ts +165 -0
- package/src/kubernetes/ready-classify.ts +76 -0
- package/src/kubernetes/ready-connect.ts +52 -0
- package/src/kubernetes/ready-declare.test.ts +85 -0
- package/src/kubernetes/ready-declare.ts +50 -0
- package/src/kubernetes/ready-errors.ts +102 -0
- package/src/kubernetes/ready-first-install.test.ts +126 -0
- package/src/kubernetes/ready-poll-states.test.ts +92 -0
- package/src/kubernetes/ready-poll.test.ts +194 -0
- package/src/kubernetes/ready-poll.ts +215 -0
- package/src/kubernetes/ready-rollout.test.ts +58 -0
- package/src/kubernetes/ready-secrecy.test.ts +131 -0
- package/src/kubernetes/ready.fixtures.ts +103 -0
- package/src/kubernetes/ready.test.ts +205 -0
- package/src/kubernetes/ready.ts +188 -0
- package/src/talos/fake-apiserver.ts +21 -3
package/README.md
CHANGED
|
@@ -69,6 +69,17 @@ const door = yield * MeshNode('vault-door', { name: 'door-a', ha: false });
|
|
|
69
69
|
|
|
70
70
|
Guide, the enrolment step and every replace case: [docs/mesh-node.md](./docs/mesh-node.md).
|
|
71
71
|
|
|
72
|
+
## CloudflaredTunnel
|
|
73
|
+
|
|
74
|
+
A remotely configured Cloudflare Tunnel declared **without its connector token in state**
|
|
75
|
+
(`Cloudflare.Tunnel.Tunnel` stores it in plaintext): [docs/cloudflared-tunnel.md](./docs/cloudflared-tunnel.md).
|
|
76
|
+
|
|
77
|
+
## SaasOidcApplication
|
|
78
|
+
|
|
79
|
+
A Cloudflare Access SaaS application of auth type `oidc` (Access as the OpenID Connect provider for
|
|
80
|
+
one relying party), exposing `issuer`, `clientId` and `jwksEndpoint`. Guide, the client-secret
|
|
81
|
+
rules, adoption and drift: [docs/saas-oidc.md](./docs/saas-oidc.md).
|
|
82
|
+
|
|
72
83
|
## Website.Astro / Website.Vite
|
|
73
84
|
|
|
74
85
|
House flags on Alchemy's own stacks — the two this estate actually ships.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `cfd_tunnel` calls a Cloudflare Tunnel (the cloudflared kind) needs, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* ★ OVER `@distilled.cloud/cloudflare`, THE SDK ALCHEMY'S OWN CLOUDFLARE PROVIDERS USE, the same
|
|
5
|
+
* one mesh-node-api.ts calls. The operations are `createTunnelCloudflared` (POST
|
|
6
|
+
* `/accounts/{account_id}/cfd_tunnel`), `getTunnelCloudflared`, `patchTunnelCloudflared`,
|
|
7
|
+
* `deleteTunnelCloudflared` and the account-wide `listTunnels` (GET `/accounts/{id}/tunnels`,
|
|
8
|
+
* filtered to `cfd_tunnel`), all in distilled `1.0.0-rc.13` `src/services/zero_trust.ts`
|
|
9
|
+
* (read 2026-10-09).
|
|
10
|
+
*
|
|
11
|
+
* ⛔ NO FUNCTION IN THIS FILE CALLS `getTunnelCloudflaredToken`, AND `observe` COPIES NAMED FIELDS
|
|
12
|
+
* ONLY. Alchemy's own `Cloudflare.Tunnel.Tunnel` (beta.81, Tunnel/Tunnel.ts `reconcile`, `read`
|
|
13
|
+
* and `list`) fetches the token on every call and stores it as a `Redacted` attribute, which
|
|
14
|
+
* `encodeState` (State/StateEncoding.ts) writes into state as `{"__redacted__": "<token>"}`:
|
|
15
|
+
* plaintext, and the token runs the tunnel. This package never holds it, so there is nothing to
|
|
16
|
+
* leak. See cloudflared-tunnel-form.ts.
|
|
17
|
+
* ⚠️ `createTunnelCloudflared` takes no `tunnelSecret` here either: the schema calls the field the
|
|
18
|
+
* password for a locally-managed tunnel and marks it optional (distilled rc.13 zero_trust.ts,
|
|
19
|
+
* `CreateTunnelCloudflaredRequest`); that Cloudflare generates one when it is omitted is
|
|
20
|
+
* UNVERIFIED, and a remotely managed tunnel needs no secret on our side.
|
|
21
|
+
*/
|
|
22
|
+
import * as zeroTrust from '@distilled.cloud/cloudflare/zero-trust';
|
|
23
|
+
import * as Effect from 'effect/Effect';
|
|
24
|
+
/** A live tunnel as this package sees it. ⛔ There is no token or secret field, on purpose. */
|
|
25
|
+
export interface ObservedTunnel {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** `undefined` when the response omitted it; only an explicit `local` is refused (lifecycle). */
|
|
29
|
+
readonly configSrc: 'cloudflare' | 'local' | undefined;
|
|
30
|
+
}
|
|
31
|
+
declare const CloudflaredTunnelError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
32
|
+
readonly _tag: "CloudflaredTunnelError";
|
|
33
|
+
} & Readonly<A>;
|
|
34
|
+
/** A refusal or failure, carrying the sentence an operator needs. Never a token. */
|
|
35
|
+
export declare class CloudflaredTunnelError extends CloudflaredTunnelError_base<{
|
|
36
|
+
readonly message: string;
|
|
37
|
+
}> {
|
|
38
|
+
}
|
|
39
|
+
type Raw = {
|
|
40
|
+
readonly id?: string | null;
|
|
41
|
+
readonly name?: string | null;
|
|
42
|
+
readonly configSrc?: string | null;
|
|
43
|
+
readonly tunType?: string | null;
|
|
44
|
+
readonly deletedAt?: string | null;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* ⚠️ A DELETED TUNNEL IS NOT A TUNNEL. Cloudflare keeps deleted tunnels (every response carries
|
|
48
|
+
* `deleted_at`), so a `GET` by id can answer for one; adopting that tombstone would PATCH it.
|
|
49
|
+
* ⚠️ NOR IS ANOTHER TUNNEL TYPE. `/tunnels` lists every type, and a `warp_connector` (a Mesh node)
|
|
50
|
+
* shares the account's name space. An item whose `tun_type` is anything but `cfd_tunnel` is not
|
|
51
|
+
* ours even when the name matches. A response with no `tun_type` is accepted: it came from a
|
|
52
|
+
* `cfd_tunnel`-scoped call.
|
|
53
|
+
*/
|
|
54
|
+
export declare const observe: (raw: Raw) => ObservedTunnel | undefined;
|
|
55
|
+
/** The tunnel with this id, or `undefined` when it is gone (404 / code 1002, or soft-deleted). */
|
|
56
|
+
export declare const getTunnel: (accountId: string, tunnelId: string) => Effect.Effect<ObservedTunnel | undefined, zeroTrust.CloudflareOpError, zeroTrust.CloudflareOpContext>;
|
|
57
|
+
/**
|
|
58
|
+
* The live cloudflared tunnel with exactly this name, or `undefined`.
|
|
59
|
+
*
|
|
60
|
+
* ★ `name` and `tunTypes` are sent as filters, but the match is re-checked here: the filter's
|
|
61
|
+
* exactness is not documented, and a prefix match would adopt the wrong tunnel.
|
|
62
|
+
* ⛔ Two live matches is refused rather than resolved. Names are unique per account (the create
|
|
63
|
+
* answers code 1013 otherwise), so two means something this package does not understand.
|
|
64
|
+
*/
|
|
65
|
+
export declare const findTunnelByName: (accountId: string, name: string) => Effect.Effect<ObservedTunnel | undefined, CloudflaredTunnelError | zeroTrust.CloudflareOpError, zeroTrust.CloudflareOpContext>;
|
|
66
|
+
/**
|
|
67
|
+
* ⛔ ALWAYS `configSrc: 'cloudflare'` (remotely managed), NEVER OMITTED. The dashboard and the
|
|
68
|
+
* ingress rules a consumer later PUTs are the remote configuration; a `local` tunnel ignores
|
|
69
|
+
* them. The SDK types the field as optional with two values (zero_trust.ts
|
|
70
|
+
* `CreateTunnelCloudflaredRequest`) and does not say which is the default, so it is sent
|
|
71
|
+
* explicitly. Create-only (the PATCH body has `name` and `tunnelSecret` only).
|
|
72
|
+
*/
|
|
73
|
+
export declare const createTunnel: (accountId: string, name: string) => Effect.Effect<ObservedTunnel, CloudflaredTunnelError | zeroTrust.CreateTunnelCloudflaredError, zeroTrust.CloudflareOpContext>;
|
|
74
|
+
/** ★ A rename is a PATCH: same id, same connectors, same `<id>.cfargotunnel.com` target. */
|
|
75
|
+
export declare const renameTunnel: (accountId: string, tunnelId: string, name: string) => Effect.Effect<ObservedTunnel, zeroTrust.PatchTunnelCloudflaredError, zeroTrust.CloudflareOpContext>;
|
|
76
|
+
/**
|
|
77
|
+
* ⛔ DELETE BY THE STORED ID ONLY, AFTER A READ BY THAT ID. Never by name: a name can have been
|
|
78
|
+
* re-used by another tunnel since this one was written, and a delete cannot be taken back. An
|
|
79
|
+
* empty id is refused before any request (a blank path segment would address the collection).
|
|
80
|
+
* ★ Idempotent: a tunnel already gone or soft-deleted is a successful delete, including one that
|
|
81
|
+
* vanishes between the read and the DELETE (see `isNotFound`). The API refuses a
|
|
82
|
+
* delete while connectors are attached ("The tunnel must have no active connections", SDK doc on
|
|
83
|
+
* `deleteTunnelCloudflared`); that error passes through, since the operator must stop cloudflared.
|
|
84
|
+
*/
|
|
85
|
+
export declare const deleteTunnel: (accountId: string, tunnelId: string) => Effect.Effect<undefined, CloudflaredTunnelError | zeroTrust.CloudflareOpError, zeroTrust.CloudflareOpContext>;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=cloudflared-tunnel-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared-tunnel-api.d.ts","sourceRoot":"","sources":["../../src/cloudflare/cloudflared-tunnel-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,SAAS,MAAM,wCAAwC,CAAC;AAEpE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;CACxD;;;;AAED,oFAAoF;AACpF,qBAAa,sBAAuB,SAAQ,4BAA2C;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;CAAG;AAEL,KAAK,GAAG,GAAG;IACT,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,QAAS,GAAG,KAAG,cAAc,GAAG,SAOnD,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,SAAS,cAAe,MAAM,YAAY,MAAM,0GAI1D,CAAC;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,cAAe,MAAM,QAAQ,MAAM,mIAe7D,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,cAAe,MAAM,QAAQ,MAAM,kIAUzD,CAAC;AAEJ,4FAA4F;AAC5F,eAAO,MAAM,YAAY,cAAe,MAAM,YAAY,MAAM,QAAQ,MAAM,wGAGc,CAAC;AAS7F;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,cAAe,MAAM,YAAY,MAAM,kHAY5D,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Cloudflare.CloudflaredTunnel` — its props, its attributes, and the pure `diff`.
|
|
3
|
+
*
|
|
4
|
+
* ⛔ THE ATTRIBUTES NEVER HOLD A TOKEN OR A SECRET. That is the reason this resource exists next to
|
|
5
|
+
* Alchemy's `Cloudflare.Tunnel.Tunnel` (beta.81): its `reconcile`, `read` and `list` all call
|
|
6
|
+
* `getTunnelCloudflaredToken` and keep the result as `token: Redacted<string>`, which
|
|
7
|
+
* `encodeState` persists as `{"__redacted__": "<token>"}` in the (unencrypted) state store. That
|
|
8
|
+
* token is what `cloudflared tunnel run --token` accepts: whoever reads state can run a connector
|
|
9
|
+
* for the tunnel and receive its traffic. It also makes every PLAN need a token with a Write
|
|
10
|
+
* permission. This resource never calls the endpoint, so a plan runs on a read token.
|
|
11
|
+
* ★ THE CONNECTOR'S TOKEN IS A RUNTIME CREDENTIAL, NOT INFRASTRUCTURE STATE. Whatever installs the
|
|
12
|
+
* connector fetches it at that moment and hands it straight to the workload's secret store.
|
|
13
|
+
* Nothing here does, and nothing here exports a helper that would.
|
|
14
|
+
* ★ SCOPE: the tunnel object only. No ingress rules, no routes, no DNS, no connector Deployment:
|
|
15
|
+
* those are separate declarations that name this tunnel's `id`.
|
|
16
|
+
*/
|
|
17
|
+
import type { Diff } from 'alchemy/Diff';
|
|
18
|
+
import type { Input } from 'alchemy/Input';
|
|
19
|
+
import { CloudflaredTunnelError } from './cloudflared-tunnel-api.ts';
|
|
20
|
+
export interface CloudflaredTunnelProps {
|
|
21
|
+
/**
|
|
22
|
+
* The tunnel's name in the account — and its identity when adopting (names are unique per
|
|
23
|
+
* account). ★ Changing it RENAMES the tunnel in place (`PATCH`): the id, the connectors and the
|
|
24
|
+
* `<id>.cfargotunnel.com` target survive.
|
|
25
|
+
*/
|
|
26
|
+
readonly name: string;
|
|
27
|
+
}
|
|
28
|
+
export interface CloudflaredTunnelAttributes {
|
|
29
|
+
/** The tunnel's UUID: the `<id>.cfargotunnel.com` target and the key for ingress rules. */
|
|
30
|
+
readonly id: string;
|
|
31
|
+
/**
|
|
32
|
+
* The account the provider environment resolved when the tunnel was written. Not a secret; it
|
|
33
|
+
* is what `delete` and `read` address, so they never act on the current environment's account.
|
|
34
|
+
*/
|
|
35
|
+
readonly accountId: string;
|
|
36
|
+
readonly name: string;
|
|
37
|
+
}
|
|
38
|
+
/** ⛔ Fail closed on a declaration the API would accept but nobody meant. */
|
|
39
|
+
export declare const validateCloudflaredTunnel: (props: CloudflaredTunnelProps) => CloudflaredTunnelError | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* update or replace, from the declaration and what was last written.
|
|
42
|
+
*
|
|
43
|
+
* - Account changed → `replace`, create-first: names are unique per ACCOUNT, so the two
|
|
44
|
+
* generations cannot collide.
|
|
45
|
+
* - Name changed → `update` (a PATCH rename).
|
|
46
|
+
* - Otherwise → no opinion; the engine compares props.
|
|
47
|
+
*/
|
|
48
|
+
export declare const diffCloudflaredTunnel: (news: Input<CloudflaredTunnelProps>, output: CloudflaredTunnelAttributes | undefined, accountId: string) => Diff | undefined;
|
|
49
|
+
//# sourceMappingURL=cloudflared-tunnel-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared-tunnel-form.d.ts","sourceRoot":"","sources":["../../src/cloudflare/cloudflared-tunnel-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC1C,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CAGvB;AAED,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,UAC7B,sBAAsB,KAC5B,sBAAsB,GAAG,SAY3B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,SAC1B,KAAK,CAAC,sBAAsB,CAAC,UAC3B,2BAA2B,GAAG,SAAS,aACpC,MAAM,KAChB,IAAI,GAAG,SAMT,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as State from 'alchemy/State';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import * as Exit from 'effect/Exit';
|
|
4
|
+
import { CloudflaredTunnel } from './cloudflared-tunnel.ts';
|
|
5
|
+
import type { CloudflaredTunnelAttributes, CloudflaredTunnelProps } from './cloudflared-tunnel-form.ts';
|
|
6
|
+
import type { FakeTunnels } from './fake-tunnel.ts';
|
|
7
|
+
export declare const ids: {
|
|
8
|
+
fqn: string;
|
|
9
|
+
id: string;
|
|
10
|
+
instanceId: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const extra: {
|
|
13
|
+
bindings: never;
|
|
14
|
+
session: never;
|
|
15
|
+
};
|
|
16
|
+
export type P = Effect.Success<typeof CloudflaredTunnel.Provider>;
|
|
17
|
+
export declare const handler: <F>(name: string, fn: F | undefined) => F;
|
|
18
|
+
/** Build the provider over the fake (as `accountId`'s environment) and hand it to `use`. */
|
|
19
|
+
export declare const run: <A, E>(fake: FakeTunnels, use: (p: P) => Effect.Effect<A, E>, accountId?: string) => Promise<A>;
|
|
20
|
+
export declare const reconcile: (p: P, news: CloudflaredTunnelProps, output?: CloudflaredTunnelAttributes) => Effect.Effect<CloudflaredTunnelAttributes, any, never>;
|
|
21
|
+
export declare const read: (p: P, olds: CloudflaredTunnelProps, output?: CloudflaredTunnelAttributes) => Effect.Effect<CloudflaredTunnelAttributes | undefined, any, never>;
|
|
22
|
+
export declare const diff: (p: P, news: CloudflaredTunnelProps, olds: CloudflaredTunnelProps, output: CloudflaredTunnelAttributes) => Effect.Effect<void | import("alchemy").Diff, any, never>;
|
|
23
|
+
/** A stored attribute set for a tunnel that may or may not exist in the fake. */
|
|
24
|
+
export declare const stored: (accountId: string, over?: Partial<CloudflaredTunnelAttributes>) => CloudflaredTunnelAttributes;
|
|
25
|
+
/** Requests the fake saw for any `/token` path. The provider must never make one. */
|
|
26
|
+
export declare const tokenReads: (fake: FakeTunnels) => number;
|
|
27
|
+
/** The writes the fake saw, in order: `['POST', 'DELETE', …]`. */
|
|
28
|
+
export declare const writes: (fake: FakeTunnels) => string[];
|
|
29
|
+
type Rows = Record<string, Record<string, Record<string, State.ResourceState>>>;
|
|
30
|
+
/**
|
|
31
|
+
* ★ THE REAL ENGINE, NOT A MODEL OF IT: Alchemy's own `Plan.make` + `apply` over an in-memory
|
|
32
|
+
* state store (the same construction as mesh-node-harness.ts, which says why
|
|
33
|
+
* `FetchHttpClient.Fetch` is provided around the whole deploy). `rows` is the store itself, so a
|
|
34
|
+
* test can serialize exactly what Alchemy would persist.
|
|
35
|
+
*/
|
|
36
|
+
export declare const engine: (fake: FakeTunnels) => {
|
|
37
|
+
deploy: <A, E, R>(declare: Effect.Effect<A, E, R>) => Promise<Exit.Exit<unknown, unknown>>;
|
|
38
|
+
rows: Rows;
|
|
39
|
+
/** The stored row's status (`created`, `replacing`, …), or `undefined` when there is none. */
|
|
40
|
+
status: (fqn: string) => "created" | "creating" | "deleting" | "replaced" | "replacing" | "updated" | "updating" | undefined;
|
|
41
|
+
};
|
|
42
|
+
/** The failure sentence of a deploy, or `''` when it succeeded. */
|
|
43
|
+
export declare const failureOf: (exit: Exit.Exit<unknown, unknown>) => string;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=cloudflared-tunnel-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared-tunnel-harness.d.ts","sourceRoot":"","sources":["../../src/cloudflare/cloudflared-tunnel-harness.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AAEvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,iBAAiB,EAA6B,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EACV,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,eAAO,MAAM,GAAG;IAAK,GAAG;IAAiB,EAAE;IAAW,UAAU;CAAS,CAAC;AAC1E,eAAO,MAAM,KAAK;IAAK,QAAQ,EAAQ,KAAK;IAAE,OAAO,EAAe,KAAK;CAAE,CAAC;AAE5E,MAAM,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AAElE,eAAO,MAAM,OAAO,GAAI,CAAC,QAAQ,MAAM,MAAM,CAAC,GAAG,SAAS,KAAG,CAG5D,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,CAAC,QAChB,WAAW,OACZ,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,cACtB,MAAM,eAUjB,CAAC;AAEJ,eAAO,MAAM,SAAS,MACjB,CAAC,QACE,sBAAsB,WACnB,2BAA2B,2DAC+B,CAAC;AAEtE,eAAO,MAAM,IAAI,MAAO,CAAC,QAAQ,sBAAsB,WAAW,2BAA2B,uEAC1C,CAAC;AAEpD,eAAO,MAAM,IAAI,MACZ,CAAC,QACE,sBAAsB,QACtB,sBAAsB,UACpB,2BAA2B,6DAKkD,CAAC;AAExF,iFAAiF;AACjF,eAAO,MAAM,MAAM,cACN,MAAM,SACX,OAAO,CAAC,2BAA2B,CAAC,KACzC,2BAKD,CAAC;AAEH,qFAAqF;AACrF,eAAO,MAAM,UAAU,SAAU,WAAW,WACe,CAAC;AAE5D,kEAAkE;AAClE,eAAO,MAAM,MAAM,SAAU,WAAW,aAC0B,CAAC;AAEnE,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAEhF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,SAAU,WAAW;aAItB,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;;IAetD,8FAA8F;kBAChF,MAAM;CAEvB,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,SAAS,SAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,WACG,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import { CloudflaredTunnelError } from './cloudflared-tunnel-api.ts';
|
|
3
|
+
import { type CloudflaredTunnelAttributes, type CloudflaredTunnelProps } from './cloudflared-tunnel-form.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Owned: refresh by the stored id. Cold (no stored row): find the live tunnel by exact name and
|
|
6
|
+
* hand it back `Unowned`, so Alchemy refuses to take it over until the stack says `adopt(true)` —
|
|
7
|
+
* a `cfd_tunnel` carries no ownership marker to prove it was ours. Adoption is idempotent: the
|
|
8
|
+
* adopted row holds the id, so every later `read` takes the owned path and writes nothing.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ A STORED ID THAT NO LONGER RESOLVES IS "MISSING", NEVER A NAME PROBE. Drift (alchemy beta.81
|
|
11
|
+
* src/Drift.ts) passes the row's output and treats whatever `read` returns as already ours
|
|
12
|
+
* (`stripUnowned`), then repairs by reconciling onto it. A by-name fallback there would write a
|
|
13
|
+
* same-named tunnel somebody else made into this row, bypassing `adopt(true)`; a later rename
|
|
14
|
+
* would PATCH it and `RemovalPolicy.destroy` would DELETE it. Returning `undefined` makes Drift
|
|
15
|
+
* report "missing" and recreate through `reconcile`, where `createFresh` names the holder.
|
|
16
|
+
*/
|
|
17
|
+
export declare const readCloudflaredTunnel: (accountId: string, olds: CloudflaredTunnelProps | undefined, output: CloudflaredTunnelAttributes | undefined) => Effect.Effect<CloudflaredTunnelAttributes | undefined, CloudflaredTunnelError | import("@distilled.cloud/cloudflare/Protocol").CloudflareOpError, import("@distilled.cloud/cloudflare/Protocol").CloudflareOpContext>;
|
|
18
|
+
export declare const reconcileCloudflaredTunnel: (accountId: string, news: CloudflaredTunnelProps, output: CloudflaredTunnelAttributes | undefined) => Effect.Effect<CloudflaredTunnelAttributes, CloudflaredTunnelError | import("@distilled.cloud/cloudflare/zero-trust").TunnelNotFound | import("@distilled.cloud/cloudflare/Protocol").CloudflareOpError, import("@distilled.cloud/cloudflare/Protocol").CloudflareOpContext>;
|
|
19
|
+
/** By the stored id and account only (cloudflared-tunnel-api.ts, `deleteTunnel`). */
|
|
20
|
+
export declare const deleteCloudflaredTunnel: (output: CloudflaredTunnelAttributes) => Effect.Effect<undefined, CloudflaredTunnelError | import("@distilled.cloud/cloudflare/Protocol").CloudflareOpError, import("@distilled.cloud/cloudflare/Protocol").CloudflareOpContext>;
|
|
21
|
+
//# sourceMappingURL=cloudflared-tunnel-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared-tunnel-lifecycle.d.ts","sourceRoot":"","sources":["../../src/cloudflare/cloudflared-tunnel-lifecycle.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EACL,sBAAsB,EAOvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAE5B,MAAM,8BAA8B,CAAC;AAQtC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,cACrB,MAAM,QACX,sBAAsB,GAAG,SAAS,UAChC,2BAA2B,GAAG,SAAS,0NAY7C,CAAC;AAkEL,eAAO,MAAM,0BAA0B,cAC1B,MAAM,QACX,sBAAsB,UACpB,2BAA2B,GAAG,SAAS,gRAiB7C,CAAC;AAEL,qFAAqF;AACrF,eAAO,MAAM,uBAAuB,WAAY,2BAA2B,4LAChC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Cloudflare.CloudflaredTunnel` — a Cloudflare Tunnel (the cloudflared kind, `cfd_tunnel`),
|
|
3
|
+
* declared without its connector token ever touching Alchemy state. Usage: docs/cloudflared-tunnel.md.
|
|
4
|
+
*
|
|
5
|
+
* 🔴 WHY THIS EXISTS ALONGSIDE `Cloudflare.Tunnel.Tunnel`. Alchemy beta.81's resource stores the
|
|
6
|
+
* token as a `Redacted` attribute, and the state encoder writes it out in plaintext. See
|
|
7
|
+
* cloudflared-tunnel-form.ts, which also says what this resource leaves to other declarations.
|
|
8
|
+
*
|
|
9
|
+
* ★ REMOVAL POLICY: `retain` BY DEFAULT — see the ★ on `CloudflaredTunnel` below.
|
|
10
|
+
*/
|
|
11
|
+
import { Credentials } from '@distilled.cloud/cloudflare/Credentials';
|
|
12
|
+
import * as Cloudflare from 'alchemy/Cloudflare';
|
|
13
|
+
import * as Provider from 'alchemy/Provider';
|
|
14
|
+
import { Resource, type ResourceClass } from 'alchemy/Resource';
|
|
15
|
+
import * as HttpClient from 'effect/http/HttpClient';
|
|
16
|
+
import { type CloudflaredTunnelAttributes, type CloudflaredTunnelProps } from './cloudflared-tunnel-form.ts';
|
|
17
|
+
import type { Providers } from './providers.ts';
|
|
18
|
+
export interface CloudflaredTunnel extends Resource<'Cloudflare.CloudflaredTunnel', CloudflaredTunnelProps, CloudflaredTunnelAttributes, never, Providers> {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* ★ `defaultRemovalPolicy: 'retain'`, LIKE EVERY KIT RESOURCE WHOSE DELETION BREAKS ITS CONSUMERS
|
|
22
|
+
* (MeshNode, the `Bao.*` families, `R2BucketLock`; the reasoning is written once in
|
|
23
|
+
* proxmox/resource.ts). Deleting a tunnel drops its remote configuration (ingress rules) and
|
|
24
|
+
* orphans every DNS record that targets `<id>.cfargotunnel.com`, and a new tunnel has a new id
|
|
25
|
+
* and a new token. So dropping the declaration, or `alchemy destroy`, leaves the tunnel live.
|
|
26
|
+
* ⚠️ IT ALSO SKIPS THE OLD TUNNEL'S DELETE IN AN ACCOUNT-CHANGE REPLACE (create-first), which
|
|
27
|
+
* leaves the old tunnel live and unmanaged (Apply.ts, `deleteOldGenerations`, beta.81).
|
|
28
|
+
* ⛔ `delete` STAYS FULLY IMPLEMENTED. Retain is Terraform's `prevent_destroy`, not a stub: it runs
|
|
29
|
+
* the moment a declaration opts in with `.pipe(RemovalPolicy.destroy())`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const CloudflaredTunnel: ResourceClass<CloudflaredTunnel>;
|
|
32
|
+
/** What every call below needs: the account, credentials and HTTP — Alchemy's own trio. */
|
|
33
|
+
export type CloudflaredTunnelServices = Cloudflare.CloudflareEnvironment | Credentials | HttpClient.HttpClient;
|
|
34
|
+
/**
|
|
35
|
+
* ★ `Provider.effect`, CAPTURING THE THREE SERVICES AT BUILD, exactly as `MeshNodeProvider` does
|
|
36
|
+
* (mesh-node.ts says why): correct whether or not the stack also merges `Cloudflare.providers()`.
|
|
37
|
+
*/
|
|
38
|
+
export declare const CloudflaredTunnelProvider: () => import("effect/Layer").Layer<Provider.Provider<CloudflaredTunnel>, never, Cloudflare.CloudflareEnvironment | Credentials | HttpClient.HttpClient>;
|
|
39
|
+
//# sourceMappingURL=cloudflared-tunnel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared-tunnel.d.ts","sourceRoot":"","sources":["../../src/cloudflare/cloudflared-tunnel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AACrD,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAG5B,MAAM,8BAA8B,CAAC;AAMtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,8BAA8B,EAC9B,sBAAsB,EACtB,2BAA2B,EAC3B,KAAK,EACL,SAAS,CACV;CAAG;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,CAG9D,CAAC;AAEF,2FAA2F;AAC3F,MAAM,MAAM,yBAAyB,GACjC,UAAU,CAAC,qBAAqB,GAChC,WAAW,GACX,UAAU,CAAC,UAAU,CAAC;AAQ1B;;;GAGG;AACH,eAAO,MAAM,yBAAyB,yJA4CnC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const TEAM = "example.cloudflareaccess.com";
|
|
2
|
+
/** ⚠️ A placeholder, not a credential. Tests assert it is stored and logged nowhere. */
|
|
3
|
+
export declare const FAKE_CLIENT_SECRET = "fake-client-secret-0123456789abcdef";
|
|
4
|
+
export type FakeApp = {
|
|
5
|
+
id: string;
|
|
6
|
+
aud: string;
|
|
7
|
+
type: string;
|
|
8
|
+
name: string;
|
|
9
|
+
session_duration: string;
|
|
10
|
+
policies: string[];
|
|
11
|
+
saas_app?: Record<string, unknown> | undefined;
|
|
12
|
+
};
|
|
13
|
+
export type Seen = {
|
|
14
|
+
readonly method: string;
|
|
15
|
+
readonly path: string;
|
|
16
|
+
readonly body: unknown;
|
|
17
|
+
};
|
|
18
|
+
/** The calls `malformed` can corrupt: `get` is the raw read, the rest are SDK calls. */
|
|
19
|
+
export type FakeOp = 'get' | 'list' | 'delete' | 'org';
|
|
20
|
+
/** How the organization read answers; an object names the `auth_domain` it returns. */
|
|
21
|
+
export type FakeOrg = 'matching' | 'unauthorized' | 'forbidden' | 'not_found' | {
|
|
22
|
+
authDomain: string;
|
|
23
|
+
};
|
|
24
|
+
export type FakeOptions = {
|
|
25
|
+
readonly perPage?: number;
|
|
26
|
+
readonly team?: string;
|
|
27
|
+
readonly org?: FakeOrg;
|
|
28
|
+
readonly malformed?: ReadonlyArray<FakeOp>;
|
|
29
|
+
};
|
|
30
|
+
export declare const fakeAccess: (options?: FakeOptions) => {
|
|
31
|
+
apps: Map<string, FakeApp>;
|
|
32
|
+
fetch: typeof fetch;
|
|
33
|
+
seed: (app: Partial<FakeApp> & {
|
|
34
|
+
name: string;
|
|
35
|
+
}) => FakeApp;
|
|
36
|
+
seen: Seen[];
|
|
37
|
+
team: string;
|
|
38
|
+
};
|
|
39
|
+
export type FakeAccess = ReturnType<typeof fakeAccess>;
|
|
40
|
+
//# sourceMappingURL=fake-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-access.d.ts","sourceRoot":"","sources":["../../src/cloudflare/fake-access.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,IAAI,iCAAiC,CAAC;AACnD,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AAExE,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9F,wFAAwF;AACxF,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACvD,uFAAuF;AACvF,MAAM,MAAM,OAAO,GACf,UAAU,GACV,cAAc,GACd,WAAW,GACX,WAAW,GACX;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3B,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC5C,CAAC;AAuCF,eAAO,MAAM,UAAU,aAAa,WAAW;;;gBAO1B,OAAO,CAAC,OAAO,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAG,OAAO;;;CAwFjE,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
@@ -34,6 +34,7 @@ export type Seen = {
|
|
|
34
34
|
readonly path: string;
|
|
35
35
|
readonly body: unknown;
|
|
36
36
|
};
|
|
37
|
+
export declare const ok: (result: unknown, extra?: Record<string, unknown>) => Response;
|
|
37
38
|
export declare const fakeFailure: (status: number, code: number, message: string) => Response;
|
|
38
39
|
export type FakeOptions = {
|
|
39
40
|
readonly perPage?: number;
|
|
@@ -52,7 +53,11 @@ export declare const fakeMesh: (options?: FakeOptions) => {
|
|
|
52
53
|
};
|
|
53
54
|
export type FakeMesh = ReturnType<typeof fakeMesh>;
|
|
54
55
|
/** distilled Credentials + the real FetchHttpClient over the fake — what a Bun script provides. */
|
|
55
|
-
export declare const fakeClientLayer: (fake:
|
|
56
|
+
export declare const fakeClientLayer: (fake: {
|
|
57
|
+
readonly fetch: typeof globalThis.fetch;
|
|
58
|
+
}, credentials?: Layer.Layer<Credentials>) => Layer.Layer<Credentials | import("effect/http/HttpClient").HttpClient, never, never>;
|
|
56
59
|
/** …plus the account, as Alchemy's CloudflareEnvironment hands it to a provider. */
|
|
57
|
-
export declare const fakeProviderLayer: (fake:
|
|
60
|
+
export declare const fakeProviderLayer: (fake: {
|
|
61
|
+
readonly fetch: typeof globalThis.fetch;
|
|
62
|
+
}, accountId?: string) => Layer.Layer<Cloudflare.CloudflareEnvironment | Credentials | import("effect/http/HttpClient").HttpClient, never, never>;
|
|
58
63
|
//# sourceMappingURL=fake-mesh.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-mesh.d.ts","sourceRoot":"","sources":["../../src/cloudflare/fake-mesh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,yCAAyC,CAAC;AACzF,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAItC,eAAO,MAAM,SAAS,sCAAsC,CAAC;AAC7D,eAAO,MAAM,YAAY,qCAAqC,CAAC;AAC/D,iFAAiF;AACjF,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"fake-mesh.d.ts","sourceRoot":"","sources":["../../src/cloudflare/fake-mesh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,yCAAyC,CAAC;AACzF,OAAO,KAAK,UAAU,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAItC,eAAO,MAAM,SAAS,sCAAsC,CAAC;AAC7D,eAAO,MAAM,YAAY,qCAAqC,CAAC;AAC/D,iFAAiF;AACjF,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9F,eAAO,MAAM,EAAE,WAAY,OAAO,UAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACY,CAAC;AAE/E,eAAO,MAAM,WAAW,WAAY,MAAM,QAAQ,MAAM,WAAW,MAAM,aAItE,CAAC;AAaJ,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF,eAAO,MAAM,QAAQ,aAAa,WAAW;;;;;iBAWvB,OAAO,CAAC,QAAQ,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAG,QAAQ;;CAyEpE,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEnD,mGAAmG;AACnG,eAAO,MAAM,eAAe,SACpB;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAE,gBACpC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,yFASpC,CAAC;AAEJ,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,SACtB;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAAE,cACtC,MAAM,4HAahB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fake Cloudflare `cfd_tunnel` API for the CloudflaredTunnel tests — an in-memory `fetch` handed
|
|
3
|
+
* to Effect's real FetchHttpClient, the same way fake-mesh.ts does it, so the tests exercise
|
|
4
|
+
* distilled's real path assembly, query and body encoding, envelope decoding and error matching.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ TEST-ONLY, AND NO NETWORK. No provider imports this file. Any request outside
|
|
7
|
+
* `/accounts/<FAKE_ACCOUNT>/cfd_tunnel` or `/accounts/<FAKE_ACCOUNT>/tunnels` throws, so a
|
|
8
|
+
* mis-wired test fails instead of reaching a real API.
|
|
9
|
+
* ★ THE FAKE HANDS OUT A TOKEN ON EVERY SURFACE IT CAN: a `token` field on the create response and
|
|
10
|
+
* on every wire object (worst case: if Cloudflare ever adds one to the documented shape), and the
|
|
11
|
+
* `/token` endpoint. The tests then prove none of it reaches an attribute, a state row or a
|
|
12
|
+
* request log. The SDK's decoder drops fields outside its schema; the provider must not depend on
|
|
13
|
+
* that alone.
|
|
14
|
+
* ★ THE NAME FILTER IS A SUBSTRING MATCH, as in fake-mesh.ts, so the client's exact re-check is
|
|
15
|
+
* exercised. `/tunnels` honours `tun_types` and `is_deleted` as the SDK documents them, and
|
|
16
|
+
* answers pages of two by default.
|
|
17
|
+
*/
|
|
18
|
+
import { type Seen } from './fake-mesh.ts';
|
|
19
|
+
export type FakeTunnel = {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
tun_type: string;
|
|
23
|
+
config_src: string;
|
|
24
|
+
status: string;
|
|
25
|
+
token: string;
|
|
26
|
+
deleted_at: string | null;
|
|
27
|
+
/** The fake refuses a DELETE while this is set, as the SDK doc says it must ("no active connections"). */
|
|
28
|
+
connected: boolean;
|
|
29
|
+
};
|
|
30
|
+
export type FakeTunnelOptions = {
|
|
31
|
+
readonly perPage?: number;
|
|
32
|
+
/** Return a Response to answer the POST with it instead (e.g. `fakeFailure(409, 1013, …)`). */
|
|
33
|
+
readonly onCreate?: (name: string) => Response | void;
|
|
34
|
+
/** Return a Response to answer the DELETE with it instead (e.g. the tunnel vanishing mid-delete). */
|
|
35
|
+
readonly onDelete?: (id: string) => Response | void;
|
|
36
|
+
};
|
|
37
|
+
export declare const fakeTunnels: (options?: FakeTunnelOptions) => {
|
|
38
|
+
auth: string[];
|
|
39
|
+
fetch: typeof fetch;
|
|
40
|
+
live: () => FakeTunnel[];
|
|
41
|
+
tunnels: Map<string, FakeTunnel>;
|
|
42
|
+
seed: (tunnel: Partial<FakeTunnel> & {
|
|
43
|
+
name: string;
|
|
44
|
+
}) => FakeTunnel;
|
|
45
|
+
seen: Seen[];
|
|
46
|
+
};
|
|
47
|
+
export type FakeTunnels = ReturnType<typeof fakeTunnels>;
|
|
48
|
+
//# sourceMappingURL=fake-tunnel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-tunnel.d.ts","sourceRoot":"","sources":["../../src/cloudflare/fake-tunnel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAgB,KAAK,IAAI,EAAmB,MAAM,gBAAgB,CAAC;AAE1E,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,0GAA0G;IAC1G,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAcF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;IACtD,qGAAqG;IACrG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;CACrD,CAAC;AAEF,eAAO,MAAM,WAAW,aAAa,iBAAiB;;;;;mBAO9B,OAAO,CAAC,UAAU,CAAC,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAG,UAAU;;CAuF1E,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cloudflare providers for Alchemy — the gaps the vendor SDK leaves.
|
|
3
3
|
*
|
|
4
|
-
* ★ Built on vendor SDKs, not hand-rolled HTTP.
|
|
5
|
-
* `@distilled.cloud/cloudflare`, the SDK Alchemy's own Cloudflare
|
|
6
|
-
* over `/r2` (`getBucketLock`/`putBucketLock`), MeshNode over
|
|
7
|
-
* `cloudflare@4.5.0` cannot create an HA node (mesh-node-api.ts).
|
|
4
|
+
* ★ Built on vendor SDKs, not hand-rolled HTTP. `R2BucketLock`, `MeshNode`, `CloudflaredTunnel` and
|
|
5
|
+
* `SaasOidcApplication` all call `@distilled.cloud/cloudflare`, the SDK Alchemy's own Cloudflare
|
|
6
|
+
* providers use — R2BucketLock over `/r2` (`getBucketLock`/`putBucketLock`), MeshNode over
|
|
7
|
+
* `/zero-trust`, because `cloudflare@4.5.0` cannot create an HA node (mesh-node-api.ts). None
|
|
8
|
+
* invents a path string.
|
|
9
|
+
* ⚠️ ONE EXCEPTION, A READ: `SaasOidcApplication` writes and looks up names through the SDK, but its
|
|
10
|
+
* responses drop `saas_app`, so `getApp` reads that one object from the wire JSON — the same
|
|
11
|
+
* `GET /accounts/{account_id}/access/apps/{app_id}` the SDK's get verb sends, over the SDK's own
|
|
12
|
+
* `HttpClient`, credentials and base URL (saas-oidc-api.ts).
|
|
8
13
|
*/
|
|
9
14
|
export type { R2LockRule } from './lock-rules.ts';
|
|
10
15
|
export { R2BucketLock, type R2BucketLockProps } from './r2-bucket-lock.ts';
|
|
@@ -12,6 +17,12 @@ export { MeshNode, MeshNodeProvider, type MeshNodeServices } from './mesh-node.t
|
|
|
12
17
|
export type { MeshNodeAttributes, MeshNodeProps } from './mesh-node-form.ts';
|
|
13
18
|
export { MeshNodeError, type MeshNodeStatus } from './mesh-node-api.ts';
|
|
14
19
|
export { fetchMeshNodeToken, type MeshNodeRef } from './mesh-node-token.ts';
|
|
20
|
+
export { CloudflaredTunnel, CloudflaredTunnelProvider, type CloudflaredTunnelServices, } from './cloudflared-tunnel.ts';
|
|
21
|
+
export type { CloudflaredTunnelAttributes, CloudflaredTunnelProps, } from './cloudflared-tunnel-form.ts';
|
|
22
|
+
export { CloudflaredTunnelError } from './cloudflared-tunnel-api.ts';
|
|
23
|
+
export { SaasOidcApplication, SaasOidcApplicationProvider } from './saas-oidc.ts';
|
|
24
|
+
export type { OidcGrantType, OidcScope, SaasOidcApplicationAttributes, SaasOidcApplicationProps, } from './saas-oidc-form.ts';
|
|
25
|
+
export { SaasOidcError } from './saas-oidc-error.ts';
|
|
15
26
|
export { providers } from './providers.ts';
|
|
16
27
|
export { astroWebsite, viteWebsite, type AstroWebsiteProps, type ViteWebsiteProps, } from './website.ts';
|
|
17
28
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACnF,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAClF,YAAY,EACV,aAAa,EACb,SAAS,EACT,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC"}
|