@hs-x/cli 0.1.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 +1001 -0
- package/dist/account-store.d.ts +51 -0
- package/dist/account-store.d.ts.map +1 -0
- package/dist/account-store.js +138 -0
- package/dist/account-store.js.map +1 -0
- package/dist/bin/hs-x.d.ts +3 -0
- package/dist/bin/hs-x.d.ts.map +1 -0
- package/dist/bin/hs-x.js +47 -0
- package/dist/bin/hs-x.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +595 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli-error.d.ts +36 -0
- package/dist/cli-error.d.ts.map +1 -0
- package/dist/cli-error.js +40 -0
- package/dist/cli-error.js.map +1 -0
- package/dist/cloudflare-auth.d.ts +25 -0
- package/dist/cloudflare-auth.d.ts.map +1 -0
- package/dist/cloudflare-auth.js +251 -0
- package/dist/cloudflare-auth.js.map +1 -0
- package/dist/cloudflare-kv.d.ts +23 -0
- package/dist/cloudflare-kv.d.ts.map +1 -0
- package/dist/cloudflare-kv.js +101 -0
- package/dist/cloudflare-kv.js.map +1 -0
- package/dist/cloudflare-oauth-store.d.ts +16 -0
- package/dist/cloudflare-oauth-store.d.ts.map +1 -0
- package/dist/cloudflare-oauth-store.js +80 -0
- package/dist/cloudflare-oauth-store.js.map +1 -0
- package/dist/cloudflare-oauth.d.ts +82 -0
- package/dist/cloudflare-oauth.d.ts.map +1 -0
- package/dist/cloudflare-oauth.js +336 -0
- package/dist/cloudflare-oauth.js.map +1 -0
- package/dist/cloudflare-pointer.d.ts +13 -0
- package/dist/cloudflare-pointer.d.ts.map +1 -0
- package/dist/cloudflare-pointer.js +46 -0
- package/dist/cloudflare-pointer.js.map +1 -0
- package/dist/command-history.d.ts +7 -0
- package/dist/command-history.d.ts.map +1 -0
- package/dist/command-history.js +34 -0
- package/dist/command-history.js.map +1 -0
- package/dist/commands/account.d.ts +7 -0
- package/dist/commands/account.d.ts.map +1 -0
- package/dist/commands/account.js +315 -0
- package/dist/commands/account.js.map +1 -0
- package/dist/commands/api.d.ts +36 -0
- package/dist/commands/api.d.ts.map +1 -0
- package/dist/commands/api.js +521 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/completion.d.ts +7 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +121 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/connect.d.ts +7 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +1123 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/control-plane-read.d.ts +22 -0
- package/dist/commands/control-plane-read.d.ts.map +1 -0
- package/dist/commands/control-plane-read.js +350 -0
- package/dist/commands/control-plane-read.js.map +1 -0
- package/dist/commands/deploy-promote.d.ts +14 -0
- package/dist/commands/deploy-promote.d.ts.map +1 -0
- package/dist/commands/deploy-promote.js +105 -0
- package/dist/commands/deploy-promote.js.map +1 -0
- package/dist/commands/deploy.d.ts +18 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +2764 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +913 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +258 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/flags.d.ts +22 -0
- package/dist/commands/flags.d.ts.map +1 -0
- package/dist/commands/flags.js +185 -0
- package/dist/commands/flags.js.map +1 -0
- package/dist/commands/help-command.d.ts +13 -0
- package/dist/commands/help-command.d.ts.map +1 -0
- package/dist/commands/help-command.js +482 -0
- package/dist/commands/help-command.js.map +1 -0
- package/dist/commands/history.d.ts +6 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +42 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +233 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/link.d.ts +26 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/link.js +441 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/login.d.ts +8 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +381 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/migrate.d.ts +8 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +258 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/rollback.d.ts +21 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/rollback.js +301 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/secrets.d.ts +7 -0
- package/dist/commands/secrets.d.ts.map +1 -0
- package/dist/commands/secrets.js +230 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +241 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/unlink.d.ts +21 -0
- package/dist/commands/unlink.d.ts.map +1 -0
- package/dist/commands/unlink.js +83 -0
- package/dist/commands/unlink.js.map +1 -0
- package/dist/commands/update.d.ts +11 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +154 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +39 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +4 -0
- package/dist/constants.js.map +1 -0
- package/dist/control-plane-fetch.d.ts +34 -0
- package/dist/control-plane-fetch.d.ts.map +1 -0
- package/dist/control-plane-fetch.js +73 -0
- package/dist/control-plane-fetch.js.map +1 -0
- package/dist/control-plane-loader.d.ts +16 -0
- package/dist/control-plane-loader.d.ts.map +1 -0
- package/dist/control-plane-loader.js +24 -0
- package/dist/control-plane-loader.js.map +1 -0
- package/dist/dev/compat-shim.d.ts +40 -0
- package/dist/dev/compat-shim.d.ts.map +1 -0
- package/dist/dev/compat-shim.js +65 -0
- package/dist/dev/compat-shim.js.map +1 -0
- package/dist/dev/event-bus.d.ts +27 -0
- package/dist/dev/event-bus.d.ts.map +1 -0
- package/dist/dev/event-bus.js +32 -0
- package/dist/dev/event-bus.js.map +1 -0
- package/dist/dev/log-server.d.ts +52 -0
- package/dist/dev/log-server.d.ts.map +1 -0
- package/dist/dev/log-server.js +216 -0
- package/dist/dev/log-server.js.map +1 -0
- package/dist/dev/session-manager.d.ts +33 -0
- package/dist/dev/session-manager.d.ts.map +1 -0
- package/dist/dev/session-manager.js +132 -0
- package/dist/dev/session-manager.js.map +1 -0
- package/dist/dev/stream-renderer.d.ts +22 -0
- package/dist/dev/stream-renderer.d.ts.map +1 -0
- package/dist/dev/stream-renderer.js +65 -0
- package/dist/dev/stream-renderer.js.map +1 -0
- package/dist/dev/tunnel.d.ts +40 -0
- package/dist/dev/tunnel.d.ts.map +1 -0
- package/dist/dev/tunnel.js +139 -0
- package/dist/dev/tunnel.js.map +1 -0
- package/dist/effect-http.d.ts +10 -0
- package/dist/effect-http.d.ts.map +1 -0
- package/dist/effect-http.js +38 -0
- package/dist/effect-http.js.map +1 -0
- package/dist/errors-registry.d.ts +11 -0
- package/dist/errors-registry.d.ts.map +1 -0
- package/dist/errors-registry.js +554 -0
- package/dist/errors-registry.js.map +1 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +30 -0
- package/dist/errors.js.map +1 -0
- package/dist/help.d.ts +6 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +100 -0
- package/dist/help.js.map +1 -0
- package/dist/history.d.ts +15 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +69 -0
- package/dist/history.js.map +1 -0
- package/dist/hubspot-auth.d.ts +53 -0
- package/dist/hubspot-auth.d.ts.map +1 -0
- package/dist/hubspot-auth.js +301 -0
- package/dist/hubspot-auth.js.map +1 -0
- package/dist/hubspot-developer-client.d.ts +10 -0
- package/dist/hubspot-developer-client.d.ts.map +1 -0
- package/dist/hubspot-developer-client.js +212 -0
- package/dist/hubspot-developer-client.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/init/templates.d.ts +18 -0
- package/dist/init/templates.d.ts.map +1 -0
- package/dist/init/templates.js +239 -0
- package/dist/init/templates.js.map +1 -0
- package/dist/load-env.d.ts +16 -0
- package/dist/load-env.d.ts.map +1 -0
- package/dist/load-env.js +69 -0
- package/dist/load-env.js.map +1 -0
- package/dist/machine-id.d.ts +3 -0
- package/dist/machine-id.d.ts.map +1 -0
- package/dist/machine-id.js +41 -0
- package/dist/machine-id.js.map +1 -0
- package/dist/paths.d.ts +4 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +19 -0
- package/dist/paths.js.map +1 -0
- package/dist/prompt.d.ts +43 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +379 -0
- package/dist/prompt.js.map +1 -0
- package/dist/reporter/human.d.ts +28 -0
- package/dist/reporter/human.d.ts.map +1 -0
- package/dist/reporter/human.js +126 -0
- package/dist/reporter/human.js.map +1 -0
- package/dist/reporter/index.d.ts +14 -0
- package/dist/reporter/index.d.ts.map +1 -0
- package/dist/reporter/index.js +37 -0
- package/dist/reporter/index.js.map +1 -0
- package/dist/reporter/json.d.ts +43 -0
- package/dist/reporter/json.d.ts.map +1 -0
- package/dist/reporter/json.js +146 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/reporter/style.d.ts +34 -0
- package/dist/reporter/style.d.ts.map +1 -0
- package/dist/reporter/style.js +97 -0
- package/dist/reporter/style.js.map +1 -0
- package/dist/reporter/types.d.ts +41 -0
- package/dist/reporter/types.d.ts.map +1 -0
- package/dist/reporter/types.js +2 -0
- package/dist/reporter/types.js.map +1 -0
- package/dist/result.d.ts +4 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +2 -0
- package/dist/result.js.map +1 -0
- package/dist/services/account-store.d.ts +31 -0
- package/dist/services/account-store.d.ts.map +1 -0
- package/dist/services/account-store.js +135 -0
- package/dist/services/account-store.js.map +1 -0
- package/dist/services/app-paths.d.ts +25 -0
- package/dist/services/app-paths.d.ts.map +1 -0
- package/dist/services/app-paths.js +34 -0
- package/dist/services/app-paths.js.map +1 -0
- package/dist/services/cloudflare-auth.d.ts +83 -0
- package/dist/services/cloudflare-auth.d.ts.map +1 -0
- package/dist/services/cloudflare-auth.js +30 -0
- package/dist/services/cloudflare-auth.js.map +1 -0
- package/dist/services/cloudflare-kv.d.ts +45 -0
- package/dist/services/cloudflare-kv.d.ts.map +1 -0
- package/dist/services/cloudflare-kv.js +151 -0
- package/dist/services/cloudflare-kv.js.map +1 -0
- package/dist/services/command-history.d.ts +29 -0
- package/dist/services/command-history.d.ts.map +1 -0
- package/dist/services/command-history.js +62 -0
- package/dist/services/command-history.js.map +1 -0
- package/dist/services/control-plane.d.ts +32 -0
- package/dist/services/control-plane.d.ts.map +1 -0
- package/dist/services/control-plane.js +57 -0
- package/dist/services/control-plane.js.map +1 -0
- package/dist/services/env-loader.d.ts +18 -0
- package/dist/services/env-loader.d.ts.map +1 -0
- package/dist/services/env-loader.js +34 -0
- package/dist/services/env-loader.js.map +1 -0
- package/dist/services/http.d.ts +19 -0
- package/dist/services/http.d.ts.map +1 -0
- package/dist/services/http.js +9 -0
- package/dist/services/http.js.map +1 -0
- package/dist/services/live.d.ts +16 -0
- package/dist/services/live.d.ts.map +1 -0
- package/dist/services/live.js +26 -0
- package/dist/services/live.js.map +1 -0
- package/dist/services/machine-id.d.ts +18 -0
- package/dist/services/machine-id.d.ts.map +1 -0
- package/dist/services/machine-id.js +39 -0
- package/dist/services/machine-id.js.map +1 -0
- package/dist/services/reporter.d.ts +55 -0
- package/dist/services/reporter.d.ts.map +1 -0
- package/dist/services/reporter.js +49 -0
- package/dist/services/reporter.js.map +1 -0
- package/dist/state-store.d.ts +39 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +89 -0
- package/dist/state-store.js.map +1 -0
- package/dist/telemetry.d.ts +13 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +129 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tenant-state.d.ts +69 -0
- package/dist/tenant-state.d.ts.map +1 -0
- package/dist/tenant-state.js +161 -0
- package/dist/tenant-state.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ErrorContext } from './reporter/types.js';
|
|
2
|
+
declare const CliError_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 & {
|
|
3
|
+
readonly _tag: "CliError";
|
|
4
|
+
} & Readonly<A>;
|
|
5
|
+
/**
|
|
6
|
+
* The single failure type that command handlers fail with. It carries a
|
|
7
|
+
* registry `code` (see `errors-registry.ts`) from which the process exit code
|
|
8
|
+
* and the user-facing help block are derived at the dispatch edge. Handlers
|
|
9
|
+
* never call `process.exit` or write errors themselves — they `Effect.fail` a
|
|
10
|
+
* `CliError` and the edge maps it once.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CliError extends CliError_base<{
|
|
13
|
+
readonly code: string;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
readonly context?: ErrorContext;
|
|
16
|
+
}> {
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Construct a `CliError`. When `message` is omitted the registry summary for
|
|
20
|
+
* `code` is used, so callers can fail with just a code for well-known errors.
|
|
21
|
+
*/
|
|
22
|
+
export declare function cliError(code: string, message?: string, context?: ErrorContext): CliError;
|
|
23
|
+
export interface ErrorDescription {
|
|
24
|
+
readonly code: string;
|
|
25
|
+
readonly message: string;
|
|
26
|
+
readonly exitCode: number;
|
|
27
|
+
readonly context: ErrorContext | undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Normalize any caught defect/failure into the fields the reporter needs and
|
|
31
|
+
* the process exit code. Unknown errors (defects, raw `Error`s that escaped a
|
|
32
|
+
* service) collapse to a generic exit code 1.
|
|
33
|
+
*/
|
|
34
|
+
export declare function describeError(error: unknown): ErrorDescription;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=cli-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-error.d.ts","sourceRoot":"","sources":["../src/cli-error.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;;;;AAExD;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,cAA6B;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;CACjC,CAAC;CAAG;AAEL;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,QAAQ,CAMzF;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAW9D"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Data } from 'effect';
|
|
2
|
+
import { getError } from './errors-registry.js';
|
|
3
|
+
/**
|
|
4
|
+
* The single failure type that command handlers fail with. It carries a
|
|
5
|
+
* registry `code` (see `errors-registry.ts`) from which the process exit code
|
|
6
|
+
* and the user-facing help block are derived at the dispatch edge. Handlers
|
|
7
|
+
* never call `process.exit` or write errors themselves — they `Effect.fail` a
|
|
8
|
+
* `CliError` and the edge maps it once.
|
|
9
|
+
*/
|
|
10
|
+
export class CliError extends Data.TaggedError('CliError') {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Construct a `CliError`. When `message` is omitted the registry summary for
|
|
14
|
+
* `code` is used, so callers can fail with just a code for well-known errors.
|
|
15
|
+
*/
|
|
16
|
+
export function cliError(code, message, context) {
|
|
17
|
+
return new CliError({
|
|
18
|
+
code,
|
|
19
|
+
message: message ?? getError(code)?.summary ?? code,
|
|
20
|
+
...(context ? { context } : {}),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Normalize any caught defect/failure into the fields the reporter needs and
|
|
25
|
+
* the process exit code. Unknown errors (defects, raw `Error`s that escaped a
|
|
26
|
+
* service) collapse to a generic exit code 1.
|
|
27
|
+
*/
|
|
28
|
+
export function describeError(error) {
|
|
29
|
+
if (error instanceof CliError) {
|
|
30
|
+
return {
|
|
31
|
+
code: error.code,
|
|
32
|
+
message: error.message,
|
|
33
|
+
exitCode: getError(error.code)?.exitCode ?? 1,
|
|
34
|
+
context: error.context,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
return { code: 'HSX_E_INTERNAL', message, exitCode: 1, context: undefined };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=cli-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-error.js","sourceRoot":"","sources":["../src/cli-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD;;;;;;GAMG;AACH,MAAM,OAAO,QAAS,SAAQ,IAAI,CAAC,WAAW,CAAC,UAAU,CAIvD;CAAG;AAEL;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,OAAgB,EAAE,OAAsB;IAC7E,OAAO,IAAI,QAAQ,CAAC;QAClB,IAAI;QACJ,OAAO,EAAE,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,IAAI,IAAI;QACnD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChC,CAAC,CAAC;AACL,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,IAAI,CAAC;YAC7C,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const CLOUDFLARE_TOKEN_TEMPLATE_URL = "https://dash.cloudflare.com/profile/api-tokens?token-name=HS-X";
|
|
2
|
+
export declare const CLOUDFLARE_REQUIRED_PERMISSIONS: readonly {
|
|
3
|
+
readonly scope: string;
|
|
4
|
+
readonly permission: string;
|
|
5
|
+
readonly permissionGroupName: string;
|
|
6
|
+
readonly reason: string;
|
|
7
|
+
readonly phase: 'phase-1' | 'phase-2';
|
|
8
|
+
}[];
|
|
9
|
+
export interface CloudflareTokenInfo {
|
|
10
|
+
readonly token: string;
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly status: string;
|
|
13
|
+
readonly accountId?: string;
|
|
14
|
+
readonly grantedPermissionGroups: readonly string[];
|
|
15
|
+
readonly missingPermissionGroups: readonly string[];
|
|
16
|
+
readonly permissionInspection: 'available' | 'unavailable';
|
|
17
|
+
readonly permissionInspectionDetail?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function verifyCloudflareToken(token: string, baseUrl?: string): Promise<CloudflareTokenInfo>;
|
|
20
|
+
export declare class CloudflareAuthError extends Error {
|
|
21
|
+
readonly code: string;
|
|
22
|
+
readonly detail: string;
|
|
23
|
+
constructor(code: string, message: string, detail: string);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=cloudflare-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-auth.d.ts","sourceRoot":"","sources":["../src/cloudflare-auth.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,6BAA6B,mEACwB,CAAC;AAKnE,eAAO,MAAM,+BAA+B,EAAE,SAAS;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;CACvC,EAyDA,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,uBAAuB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpD,QAAQ,CAAC,uBAAuB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpD,QAAQ,CAAC,oBAAoB,EAAE,WAAW,GAAG,aAAa,CAAC;IAC3D,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;CAC9C;AAmQD,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAqC,GAC7C,OAAO,CAAC,mBAAmB,CAAC,CAkB9B;AAgCD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBACZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM1D"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { HsxHttpClientRaw, HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse, } from '@hs-x/types';
|
|
2
|
+
import { Cause, Effect, Exit, Option, Schema } from 'effect';
|
|
3
|
+
import { CloudflareAccountListFailed, CloudflareTokenInvalid, CloudflareTokenMissingPermissions, } from './errors.js';
|
|
4
|
+
export const CLOUDFLARE_TOKEN_TEMPLATE_URL = 'https://dash.cloudflare.com/profile/api-tokens?token-name=HS-X';
|
|
5
|
+
// Permissions HS-X exercises across the current deploy surface plus the Phase 2
|
|
6
|
+
// observability/logging surface. Used in prompt copy and best-effort token
|
|
7
|
+
// introspection after the user pastes a token.
|
|
8
|
+
export const CLOUDFLARE_REQUIRED_PERMISSIONS = [
|
|
9
|
+
{
|
|
10
|
+
scope: 'Account · Workers Scripts',
|
|
11
|
+
permission: 'Edit',
|
|
12
|
+
permissionGroupName: 'Workers Scripts Write',
|
|
13
|
+
reason: 'deploy Worker scripts, bindings, triggers, and routes',
|
|
14
|
+
phase: 'phase-1',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
scope: 'Account · Workers KV Storage',
|
|
18
|
+
permission: 'Edit',
|
|
19
|
+
permissionGroupName: 'Workers KV Storage Write',
|
|
20
|
+
reason: 'create and update runtime KV namespaces',
|
|
21
|
+
phase: 'phase-1',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
scope: 'Account · D1',
|
|
25
|
+
permission: 'Edit',
|
|
26
|
+
permissionGroupName: 'D1 Write',
|
|
27
|
+
reason: 'create and migrate per-project D1 databases',
|
|
28
|
+
phase: 'phase-1',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
scope: 'Account · Queues',
|
|
32
|
+
permission: 'Edit',
|
|
33
|
+
permissionGroupName: 'Queues Write',
|
|
34
|
+
reason: 'provision queues for async sync and batched work',
|
|
35
|
+
phase: 'phase-1',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
scope: 'Account · Workers Tail',
|
|
39
|
+
permission: 'Read',
|
|
40
|
+
permissionGroupName: 'Workers Tail Read',
|
|
41
|
+
reason: 'stream live Worker logs during dev and debugging',
|
|
42
|
+
phase: 'phase-1',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
scope: 'Account · Account Settings',
|
|
46
|
+
permission: 'Read',
|
|
47
|
+
permissionGroupName: 'Account Settings Read',
|
|
48
|
+
reason: 'discover and validate the selected Cloudflare account',
|
|
49
|
+
phase: 'phase-1',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
scope: 'Account · R2 Storage',
|
|
53
|
+
permission: 'Edit',
|
|
54
|
+
permissionGroupName: 'Workers R2 Storage Write',
|
|
55
|
+
reason: 'store deploy bundles, archived logs, and large artifacts',
|
|
56
|
+
phase: 'phase-2',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
scope: 'Account · Account Analytics',
|
|
60
|
+
permission: 'Read',
|
|
61
|
+
permissionGroupName: 'Account Analytics Read',
|
|
62
|
+
reason: 'query Analytics Engine for usage, logs, and billing views',
|
|
63
|
+
phase: 'phase-2',
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
const apiGet = (input) => Effect.gen(function* () {
|
|
67
|
+
const client = yield* HttpClient.HttpClient;
|
|
68
|
+
return yield* client
|
|
69
|
+
.execute(HttpClientRequest.get(input.url).pipe(HttpClientRequest.bearerToken(input.token), HttpClientRequest.acceptJson))
|
|
70
|
+
.pipe(Effect.scoped);
|
|
71
|
+
});
|
|
72
|
+
const CloudflareTokenPolicySchema = Schema.Struct({
|
|
73
|
+
effect: Schema.optional(Schema.String),
|
|
74
|
+
permission_groups: Schema.optional(Schema.Array(Schema.Struct({
|
|
75
|
+
name: Schema.optional(Schema.String),
|
|
76
|
+
}))),
|
|
77
|
+
});
|
|
78
|
+
const VerifyBodySchema = Schema.Struct({
|
|
79
|
+
success: Schema.optional(Schema.Boolean),
|
|
80
|
+
result: Schema.optional(Schema.Struct({
|
|
81
|
+
id: Schema.optional(Schema.String),
|
|
82
|
+
status: Schema.optional(Schema.String),
|
|
83
|
+
policies: Schema.optional(Schema.Array(CloudflareTokenPolicySchema)),
|
|
84
|
+
})),
|
|
85
|
+
errors: Schema.optional(Schema.Array(Schema.Struct({
|
|
86
|
+
code: Schema.optional(Schema.Number),
|
|
87
|
+
message: Schema.optional(Schema.String),
|
|
88
|
+
}))),
|
|
89
|
+
});
|
|
90
|
+
const DetailsBodySchema = Schema.Struct({
|
|
91
|
+
success: Schema.optional(Schema.Boolean),
|
|
92
|
+
result: Schema.optional(Schema.Struct({
|
|
93
|
+
policies: Schema.optional(Schema.Array(CloudflareTokenPolicySchema)),
|
|
94
|
+
})),
|
|
95
|
+
errors: Schema.optional(Schema.Array(Schema.Struct({
|
|
96
|
+
message: Schema.optional(Schema.String),
|
|
97
|
+
}))),
|
|
98
|
+
});
|
|
99
|
+
const AccountListBodySchema = Schema.Struct({
|
|
100
|
+
result: Schema.optional(Schema.Array(Schema.Struct({
|
|
101
|
+
id: Schema.optional(Schema.String),
|
|
102
|
+
}))),
|
|
103
|
+
});
|
|
104
|
+
const readVerifyBody = (response) => HttpClientResponse.schemaBodyJson(VerifyBodySchema)(response).pipe(Effect.catchAll(() => Effect.succeed({})));
|
|
105
|
+
const readDetailsBody = (response) => HttpClientResponse.schemaBodyJson(DetailsBodySchema)(response).pipe(Effect.catchAll(() => Effect.succeed({})));
|
|
106
|
+
const readAccountListBody = (response) => HttpClientResponse.schemaBodyJson(AccountListBodySchema)(response).pipe(Effect.catchAll(() => Effect.succeed({})));
|
|
107
|
+
const isStatusOk = (status) => status >= 200 && status < 300;
|
|
108
|
+
const verifyToken = (token, baseUrl) => Effect.gen(function* () {
|
|
109
|
+
const response = yield* apiGet({
|
|
110
|
+
endpoint: '/client/v4/user/tokens/verify',
|
|
111
|
+
url: new URL('/client/v4/user/tokens/verify', baseUrl),
|
|
112
|
+
token,
|
|
113
|
+
});
|
|
114
|
+
const body = yield* readVerifyBody(response);
|
|
115
|
+
if (!isStatusOk(response.status) || body.success === false || !body.result?.id) {
|
|
116
|
+
return yield* Effect.fail(new CloudflareTokenInvalid({
|
|
117
|
+
detail: body.errors?.[0]?.message ?? `verify returned ${response.status}`,
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
return body.result;
|
|
121
|
+
});
|
|
122
|
+
const inspectPermissions = (input) => Effect.gen(function* () {
|
|
123
|
+
const fromVerify = permissionGroupsFromPolicies(input.verifyPolicies);
|
|
124
|
+
if (fromVerify.length > 0) {
|
|
125
|
+
return { grantedPermissionGroups: fromVerify, permissionInspection: 'available' };
|
|
126
|
+
}
|
|
127
|
+
const endpoint = `/client/v4/user/tokens/${encodeURIComponent(input.tokenId)}`;
|
|
128
|
+
const response = yield* apiGet({
|
|
129
|
+
endpoint,
|
|
130
|
+
url: new URL(endpoint, input.baseUrl),
|
|
131
|
+
token: input.token,
|
|
132
|
+
});
|
|
133
|
+
if (!isStatusOk(response.status)) {
|
|
134
|
+
return {
|
|
135
|
+
grantedPermissionGroups: [],
|
|
136
|
+
permissionInspection: 'unavailable',
|
|
137
|
+
permissionInspectionDetail: `Cloudflare token details returned HTTP ${response.status}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const body = yield* readDetailsBody(response);
|
|
141
|
+
if (body.success === false) {
|
|
142
|
+
return {
|
|
143
|
+
grantedPermissionGroups: [],
|
|
144
|
+
permissionInspection: 'unavailable',
|
|
145
|
+
permissionInspectionDetail: body.errors?.[0]?.message ?? 'Cloudflare token details were unavailable.',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
grantedPermissionGroups: permissionGroupsFromPolicies(body.result?.policies),
|
|
150
|
+
permissionInspection: 'available',
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
const listFirstAccountId = (token, baseUrl) => {
|
|
154
|
+
const endpoint = '/client/v4/accounts';
|
|
155
|
+
return Effect.gen(function* () {
|
|
156
|
+
const response = yield* apiGet({ endpoint, url: new URL(endpoint, baseUrl), token });
|
|
157
|
+
if (!isStatusOk(response.status)) {
|
|
158
|
+
return yield* Effect.fail(new CloudflareAccountListFailed({
|
|
159
|
+
detail: `accounts returned HTTP ${response.status}`,
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
const body = yield* readAccountListBody(response);
|
|
163
|
+
return body.result?.[0]?.id;
|
|
164
|
+
}).pipe(
|
|
165
|
+
// The account list is best-effort: surface undefined on any failure
|
|
166
|
+
// (HTTP, timeout, account-list failed) rather than failing the whole flow.
|
|
167
|
+
Effect.catchAll(() => Effect.succeed(undefined)));
|
|
168
|
+
};
|
|
169
|
+
const verifyProgram = (token, baseUrl) => Effect.gen(function* () {
|
|
170
|
+
const verified = yield* verifyToken(token, baseUrl);
|
|
171
|
+
const inspected = yield* inspectPermissions({
|
|
172
|
+
token,
|
|
173
|
+
tokenId: verified.id,
|
|
174
|
+
baseUrl,
|
|
175
|
+
...(verified.policies ? { verifyPolicies: verified.policies } : {}),
|
|
176
|
+
});
|
|
177
|
+
const accountId = yield* listFirstAccountId(token, baseUrl);
|
|
178
|
+
return {
|
|
179
|
+
token,
|
|
180
|
+
id: verified.id,
|
|
181
|
+
status: verified.status ?? 'active',
|
|
182
|
+
grantedPermissionGroups: inspected.grantedPermissionGroups,
|
|
183
|
+
missingPermissionGroups: missingPermissionGroups(inspected.grantedPermissionGroups),
|
|
184
|
+
permissionInspection: inspected.permissionInspection,
|
|
185
|
+
...(accountId ? { accountId } : {}),
|
|
186
|
+
...(inspected.permissionInspectionDetail
|
|
187
|
+
? { permissionInspectionDetail: inspected.permissionInspectionDetail }
|
|
188
|
+
: {}),
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
const toCloudflareAuthError = (err) => {
|
|
192
|
+
switch (err._tag) {
|
|
193
|
+
case 'CloudflareTokenInvalid':
|
|
194
|
+
return new CloudflareAuthError('HSX_E_CLOUDFLARE_TOKEN_INVALID', 'Cloudflare token verification failed.', err.detail);
|
|
195
|
+
case 'CloudflareTokenMissingPermissions':
|
|
196
|
+
return new CloudflareAuthError('HSX_E_CLOUDFLARE_TOKEN_PERMISSIONS', 'Cloudflare token is missing required permissions.', err.detail);
|
|
197
|
+
case 'RequestError':
|
|
198
|
+
return new CloudflareAuthError('HSX_E_CLOUDFLARE_TOKEN_VERIFY', 'Cloudflare token verification failed.', err.description ?? err.message);
|
|
199
|
+
case 'ResponseError':
|
|
200
|
+
return new CloudflareAuthError('HSX_E_CLOUDFLARE_TOKEN_VERIFY', 'Cloudflare token verification failed.', err.description ?? err.message);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
export async function verifyCloudflareToken(token, baseUrl = 'https://api.cloudflare.com') {
|
|
204
|
+
const exit = await Effect.runPromise(Effect.exit(verifyProgram(token, baseUrl).pipe(Effect.provide(HsxHttpClientRaw))));
|
|
205
|
+
return Exit.match(exit, {
|
|
206
|
+
onSuccess: (info) => info,
|
|
207
|
+
onFailure: (cause) => {
|
|
208
|
+
const failure = Cause.failureOption(cause);
|
|
209
|
+
if (Option.isSome(failure)) {
|
|
210
|
+
throw toCloudflareAuthError(failure.value);
|
|
211
|
+
}
|
|
212
|
+
throw new CloudflareAuthError('HSX_E_CLOUDFLARE_TOKEN_VERIFY', 'Cloudflare token verification failed.', Cause.pretty(cause));
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function permissionGroupsFromPolicies(policies) {
|
|
217
|
+
const names = new Set();
|
|
218
|
+
for (const policy of policies ?? []) {
|
|
219
|
+
if (policy.effect && policy.effect !== 'allow')
|
|
220
|
+
continue;
|
|
221
|
+
for (const group of policy.permission_groups ?? []) {
|
|
222
|
+
if (group.name)
|
|
223
|
+
names.add(group.name);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return [...names].sort((a, b) => a.localeCompare(b));
|
|
227
|
+
}
|
|
228
|
+
function missingPermissionGroups(grantedPermissionGroups) {
|
|
229
|
+
if (grantedPermissionGroups.length === 0) {
|
|
230
|
+
return CLOUDFLARE_REQUIRED_PERMISSIONS.map((permission) => permission.permissionGroupName);
|
|
231
|
+
}
|
|
232
|
+
const granted = new Set(grantedPermissionGroups.map(normalizePermissionGroupName));
|
|
233
|
+
return CLOUDFLARE_REQUIRED_PERMISSIONS.filter((permission) => !granted.has(normalizePermissionGroupName(permission.permissionGroupName))).map((permission) => permission.permissionGroupName);
|
|
234
|
+
}
|
|
235
|
+
function normalizePermissionGroupName(value) {
|
|
236
|
+
return value
|
|
237
|
+
.toLowerCase()
|
|
238
|
+
.replace(/[^a-z0-9]+/g, ' ')
|
|
239
|
+
.trim();
|
|
240
|
+
}
|
|
241
|
+
export class CloudflareAuthError extends Error {
|
|
242
|
+
code;
|
|
243
|
+
detail;
|
|
244
|
+
constructor(code, message, detail) {
|
|
245
|
+
super(message);
|
|
246
|
+
this.name = 'CloudflareAuthError';
|
|
247
|
+
this.code = code;
|
|
248
|
+
this.detail = detail;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=cloudflare-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-auth.js","sourceRoot":"","sources":["../src/cloudflare-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CloudflareKvNamespace {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly title: string;
|
|
4
|
+
}
|
|
5
|
+
export interface CloudflareKvClient {
|
|
6
|
+
ensureNamespace(name: string): Promise<CloudflareKvNamespace>;
|
|
7
|
+
get(key: string): Promise<string | undefined>;
|
|
8
|
+
put(key: string, value: string): Promise<void>;
|
|
9
|
+
list(prefix: string): Promise<readonly string[]>;
|
|
10
|
+
delete(key: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare function createCloudflareKvClient(input: {
|
|
13
|
+
readonly accountId: string;
|
|
14
|
+
readonly apiToken: string;
|
|
15
|
+
readonly namespaceId?: string;
|
|
16
|
+
readonly baseUrl?: string;
|
|
17
|
+
readonly fetchImpl?: typeof fetch;
|
|
18
|
+
}): CloudflareKvClient;
|
|
19
|
+
export declare function resolveCloudflareCredentials(argv: readonly string[]): {
|
|
20
|
+
readonly apiToken: string | undefined;
|
|
21
|
+
readonly accountId: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=cloudflare-kv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-kv.d.ts","sourceRoot":"","sources":["../src/cloudflare-kv.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACnC,GAAG,kBAAkB,CAuHrB;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,CAYA"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export function createCloudflareKvClient(input) {
|
|
2
|
+
const fetchImpl = input.fetchImpl ?? fetch;
|
|
3
|
+
const baseUrl = input.baseUrl ?? 'https://api.cloudflare.com';
|
|
4
|
+
let namespaceId = input.namespaceId;
|
|
5
|
+
const api = async (path, init = {}) => {
|
|
6
|
+
const response = await fetchImpl(new URL(path, baseUrl), {
|
|
7
|
+
...init,
|
|
8
|
+
headers: {
|
|
9
|
+
authorization: `Bearer ${input.apiToken}`,
|
|
10
|
+
...(init.body ? { 'content-type': 'application/json' } : {}),
|
|
11
|
+
...(init.headers ?? {}),
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
const detail = await response.text().catch(() => '');
|
|
16
|
+
throw new Error(`Cloudflare KV request failed (${response.status})${detail ? `: ${detail}` : ''}`);
|
|
17
|
+
}
|
|
18
|
+
return response;
|
|
19
|
+
};
|
|
20
|
+
const requireNamespaceId = () => {
|
|
21
|
+
if (!namespaceId)
|
|
22
|
+
throw new Error('Cloudflare KV namespace has not been initialized.');
|
|
23
|
+
return namespaceId;
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
async ensureNamespace(name) {
|
|
27
|
+
const listResponse = await api(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces`);
|
|
28
|
+
const listBody = (await listResponse.json());
|
|
29
|
+
const existing = listBody.result?.find((item) => item.title === name);
|
|
30
|
+
if (existing?.id && existing.title) {
|
|
31
|
+
namespaceId = existing.id;
|
|
32
|
+
return { id: existing.id, title: existing.title };
|
|
33
|
+
}
|
|
34
|
+
const createResponse = await api(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces`, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
body: JSON.stringify({ title: name }),
|
|
37
|
+
});
|
|
38
|
+
const createBody = (await createResponse.json());
|
|
39
|
+
if (!createBody.result?.id) {
|
|
40
|
+
throw new Error('Cloudflare KV namespace create response did not include an id.');
|
|
41
|
+
}
|
|
42
|
+
namespaceId = createBody.result.id;
|
|
43
|
+
return { id: createBody.result.id, title: createBody.result.title ?? name };
|
|
44
|
+
},
|
|
45
|
+
async get(key) {
|
|
46
|
+
const response = await fetchImpl(new URL(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(requireNamespaceId())}/values/${encodeURIComponent(key)}`, baseUrl), {
|
|
47
|
+
headers: { authorization: `Bearer ${input.apiToken}` },
|
|
48
|
+
});
|
|
49
|
+
if (response.status === 404)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
throw new Error(`Cloudflare KV get failed (${response.status}).`);
|
|
53
|
+
}
|
|
54
|
+
return await response.text();
|
|
55
|
+
},
|
|
56
|
+
async put(key, value) {
|
|
57
|
+
await api(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(requireNamespaceId())}/values/${encodeURIComponent(key)}`, {
|
|
58
|
+
method: 'PUT',
|
|
59
|
+
body: value,
|
|
60
|
+
headers: { 'content-type': 'text/plain' },
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
async list(prefix) {
|
|
64
|
+
const keys = [];
|
|
65
|
+
let cursor;
|
|
66
|
+
do {
|
|
67
|
+
const url = new URL(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(requireNamespaceId())}/keys`, baseUrl);
|
|
68
|
+
url.searchParams.set('prefix', prefix);
|
|
69
|
+
if (cursor)
|
|
70
|
+
url.searchParams.set('cursor', cursor);
|
|
71
|
+
const response = await api(`${url.pathname}${url.search}`);
|
|
72
|
+
const body = (await response.json());
|
|
73
|
+
keys.push(...(body.result ?? []).flatMap((item) => (item.name ? [item.name] : [])));
|
|
74
|
+
cursor = body.result_info?.cursor || undefined;
|
|
75
|
+
} while (cursor);
|
|
76
|
+
return keys;
|
|
77
|
+
},
|
|
78
|
+
async delete(key) {
|
|
79
|
+
await api(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(requireNamespaceId())}/values/${encodeURIComponent(key)}`, { method: 'DELETE' });
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function resolveCloudflareCredentials(argv) {
|
|
84
|
+
return {
|
|
85
|
+
apiToken: resolveFlag(argv, '--cloudflare-api-token') ??
|
|
86
|
+
resolveFlag(argv, '--api-token') ??
|
|
87
|
+
process.env.HSX_CLOUDFLARE_API_TOKEN ??
|
|
88
|
+
process.env.CLOUDFLARE_API_TOKEN,
|
|
89
|
+
accountId: resolveFlag(argv, '--cloudflare-account-id') ??
|
|
90
|
+
process.env.HSX_CLOUDFLARE_ACCOUNT_ID ??
|
|
91
|
+
process.env.CLOUDFLARE_ACCOUNT_ID,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function resolveFlag(argv, name) {
|
|
95
|
+
const eq = argv.find((arg) => arg.startsWith(`${name}=`));
|
|
96
|
+
if (eq)
|
|
97
|
+
return eq.slice(name.length + 1);
|
|
98
|
+
const idx = argv.indexOf(name);
|
|
99
|
+
return idx >= 0 ? argv[idx + 1] : undefined;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=cloudflare-kv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-kv.js","sourceRoot":"","sources":["../src/cloudflare-kv.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface CloudflareOAuthCredential {
|
|
2
|
+
readonly refreshToken: string;
|
|
3
|
+
readonly scope?: string;
|
|
4
|
+
readonly updatedAt: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CloudflareOAuthStore {
|
|
7
|
+
readonly schemaVersion: 1;
|
|
8
|
+
readonly credentials: Record<string, CloudflareOAuthCredential>;
|
|
9
|
+
}
|
|
10
|
+
export declare function defaultCloudflareOAuthStorePath(): string;
|
|
11
|
+
export declare function saveCloudflareOAuthCredential(cloudflareAccountId: string, credential: Omit<CloudflareOAuthCredential, 'updatedAt'>, options?: {
|
|
12
|
+
path?: string;
|
|
13
|
+
now?: () => Date;
|
|
14
|
+
}): Promise<CloudflareOAuthStore>;
|
|
15
|
+
export declare function getCloudflareOAuthCredential(cloudflareAccountId: string, path?: string): Promise<CloudflareOAuthCredential | undefined>;
|
|
16
|
+
//# sourceMappingURL=cloudflare-oauth-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-oauth-store.d.ts","sourceRoot":"","sources":["../src/cloudflare-oauth-store.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;CACjE;AAID,wBAAgB,+BAA+B,IAAI,MAAM,CAIxD;AAyBD,wBAAsB,6BAA6B,CACjD,mBAAmB,EAAE,MAAM,EAC3B,UAAU,EAAE,IAAI,CAAC,yBAAyB,EAAE,WAAW,CAAC,EACxD,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GAChD,OAAO,CAAC,oBAAoB,CAAC,CAoB/B;AAED,wBAAsB,4BAA4B,CAChD,mBAAmB,EAAE,MAAM,EAC3B,IAAI,GAAE,MAA0C,GAC/C,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CAGhD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Persistence for Cloudflare OAuth refresh tokens, keyed by Cloudflare
|
|
2
|
+
// account id so a single user with multiple CF accounts has separate
|
|
3
|
+
// credentials per account.
|
|
4
|
+
//
|
|
5
|
+
// File layout (default `$XDG_CONFIG_HOME/hs-x/cloudflare-oauth.json`):
|
|
6
|
+
//
|
|
7
|
+
// {
|
|
8
|
+
// "schemaVersion": 1,
|
|
9
|
+
// "credentials": {
|
|
10
|
+
// "<cloudflareAccountId>": {
|
|
11
|
+
// "refreshToken": "...",
|
|
12
|
+
// "scope": "...",
|
|
13
|
+
// "updatedAt": "ISO"
|
|
14
|
+
// }
|
|
15
|
+
// }
|
|
16
|
+
// }
|
|
17
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
18
|
+
import { dirname } from 'node:path';
|
|
19
|
+
import { configPath } from './paths.js';
|
|
20
|
+
const EMPTY_STORE = { schemaVersion: 1, credentials: {} };
|
|
21
|
+
export function defaultCloudflareOAuthStorePath() {
|
|
22
|
+
const override = process.env.HSX_CLOUDFLARE_OAUTH_STORE_PATH;
|
|
23
|
+
if (override && override.length > 0)
|
|
24
|
+
return override;
|
|
25
|
+
return configPath('cloudflare-oauth.json');
|
|
26
|
+
}
|
|
27
|
+
async function loadCloudflareOAuthStore(path = defaultCloudflareOAuthStorePath()) {
|
|
28
|
+
try {
|
|
29
|
+
const raw = await readFile(path, 'utf8');
|
|
30
|
+
const parsed = JSON.parse(raw);
|
|
31
|
+
const credentials = {};
|
|
32
|
+
if (parsed.credentials && typeof parsed.credentials === 'object') {
|
|
33
|
+
for (const [id, value] of Object.entries(parsed.credentials)) {
|
|
34
|
+
if (!isCredential(value))
|
|
35
|
+
continue;
|
|
36
|
+
credentials[id] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { schemaVersion: 1, credentials };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return EMPTY_STORE;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function saveCloudflareOAuthCredential(cloudflareAccountId, credential, options = {}) {
|
|
46
|
+
const path = options.path ?? defaultCloudflareOAuthStorePath();
|
|
47
|
+
const store = await loadCloudflareOAuthStore(path);
|
|
48
|
+
const updatedAt = (options.now ? options.now() : new Date()).toISOString();
|
|
49
|
+
const next = {
|
|
50
|
+
schemaVersion: 1,
|
|
51
|
+
credentials: {
|
|
52
|
+
...store.credentials,
|
|
53
|
+
[cloudflareAccountId]: { ...credential, updatedAt },
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
await mkdir(dirname(path), { recursive: true });
|
|
57
|
+
await writeFile(path, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
|
|
58
|
+
// refresh tokens are bearer-equivalent — restrict file perms
|
|
59
|
+
try {
|
|
60
|
+
await chmod(path, 0o600);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// best-effort on platforms without POSIX perms
|
|
64
|
+
}
|
|
65
|
+
return next;
|
|
66
|
+
}
|
|
67
|
+
export async function getCloudflareOAuthCredential(cloudflareAccountId, path = defaultCloudflareOAuthStorePath()) {
|
|
68
|
+
const store = await loadCloudflareOAuthStore(path);
|
|
69
|
+
return store.credentials[cloudflareAccountId];
|
|
70
|
+
}
|
|
71
|
+
function isCredential(value) {
|
|
72
|
+
if (!value || typeof value !== 'object')
|
|
73
|
+
return false;
|
|
74
|
+
const v = value;
|
|
75
|
+
return (typeof v.refreshToken === 'string' &&
|
|
76
|
+
v.refreshToken.length > 0 &&
|
|
77
|
+
typeof v.updatedAt === 'string' &&
|
|
78
|
+
(v.scope === undefined || typeof v.scope === 'string'));
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=cloudflare-oauth-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-oauth-store.js","sourceRoot":"","sources":["../src/cloudflare-oauth-store.ts"],"names":[],"mappings":"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"}
|