hooklatch 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +438 -2
- package/dist/adapters/cloudflare.d.ts +11 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -0
- package/dist/adapters/cloudflare.js +27 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/express.d.ts +9 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +63 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/hono.d.ts +12 -0
- package/dist/adapters/hono.d.ts.map +1 -0
- package/dist/adapters/hono.js +28 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/adapters/nextjs.d.ts +6 -0
- package/dist/adapters/nextjs.d.ts.map +1 -0
- package/dist/adapters/nextjs.js +56 -0
- package/dist/adapters/nextjs.js.map +1 -0
- package/dist/adapters/shared.d.ts +8 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/shared.js +53 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/cjs/adapters/cloudflare.cjs +29 -0
- package/dist/cjs/adapters/cloudflare.d.cts +10 -0
- package/dist/cjs/adapters/express.cjs +65 -0
- package/dist/cjs/adapters/express.d.cts +8 -0
- package/dist/cjs/adapters/hono.cjs +30 -0
- package/dist/cjs/adapters/hono.d.cts +11 -0
- package/dist/cjs/adapters/nextjs.cjs +58 -0
- package/dist/cjs/adapters/nextjs.d.cts +5 -0
- package/dist/cjs/adapters/shared.cjs +58 -0
- package/dist/cjs/adapters/shared.d.cts +7 -0
- package/dist/cjs/core.cjs +30 -0
- package/dist/cjs/core.d.cts +5 -0
- package/dist/cjs/diagnostics/catalog.cjs +341 -0
- package/dist/cjs/diagnostics/catalog.d.cts +19 -0
- package/dist/cjs/diagnostics/index.cjs +90 -0
- package/dist/cjs/diagnostics/index.d.cts +5 -0
- package/dist/cjs/diagnostics/types.cjs +2 -0
- package/dist/cjs/diagnostics/types.d.cts +20 -0
- package/dist/cjs/errors.cjs +13 -0
- package/dist/cjs/errors.d.cts +6 -0
- package/dist/cjs/index.cjs +9 -0
- package/dist/cjs/index.d.cts +3 -0
- package/dist/cjs/internal/body.cjs +50 -0
- package/dist/cjs/internal/body.d.cts +2 -0
- package/dist/cjs/internal/bytes.cjs +43 -0
- package/dist/cjs/internal/bytes.d.cts +4 -0
- package/dist/cjs/internal/crypto.cjs +52 -0
- package/dist/cjs/internal/crypto.d.cts +3 -0
- package/dist/cjs/internal/headers.cjs +72 -0
- package/dist/cjs/internal/headers.d.cts +2 -0
- package/dist/cjs/internal/options.cjs +130 -0
- package/dist/cjs/internal/options.d.cts +7 -0
- package/dist/cjs/internal/prepare.cjs +11 -0
- package/dist/cjs/internal/prepare.d.cts +4 -0
- package/dist/cjs/internal/provider-options.cjs +72 -0
- package/dist/cjs/internal/provider-options.d.cts +6 -0
- package/dist/cjs/internal/provider.cjs +2 -0
- package/dist/cjs/internal/provider.d.cts +39 -0
- package/dist/cjs/internal/verification.cjs +71 -0
- package/dist/cjs/internal/verification.d.cts +12 -0
- package/dist/cjs/providers/clerk.cjs +15 -0
- package/dist/cjs/providers/clerk.d.cts +9 -0
- package/dist/cjs/providers/dodo-payments.cjs +26 -0
- package/dist/cjs/providers/dodo-payments.d.cts +20 -0
- package/dist/cjs/providers/doppler.cjs +71 -0
- package/dist/cjs/providers/doppler.d.cts +37 -0
- package/dist/cjs/providers/fal.cjs +80 -0
- package/dist/cjs/providers/fal.d.cts +13 -0
- package/dist/cjs/providers/github.cjs +52 -0
- package/dist/cjs/providers/github.d.cts +7 -0
- package/dist/cjs/providers/gitlab.cjs +26 -0
- package/dist/cjs/providers/gitlab.d.cts +20 -0
- package/dist/cjs/providers/grafana.cjs +180 -0
- package/dist/cjs/providers/grafana.d.cts +35 -0
- package/dist/cjs/providers/index.cjs +110 -0
- package/dist/cjs/providers/index.d.cts +26 -0
- package/dist/cjs/providers/lemon-squeezy.cjs +36 -0
- package/dist/cjs/providers/lemon-squeezy.d.cts +15 -0
- package/dist/cjs/providers/linear.cjs +58 -0
- package/dist/cjs/providers/linear.d.cts +36 -0
- package/dist/cjs/providers/paddle.cjs +105 -0
- package/dist/cjs/providers/paddle.d.cts +14 -0
- package/dist/cjs/providers/polar.cjs +80 -0
- package/dist/cjs/providers/polar.d.cts +25 -0
- package/dist/cjs/providers/razorpay.cjs +43 -0
- package/dist/cjs/providers/razorpay.d.cts +19 -0
- package/dist/cjs/providers/replicate.cjs +25 -0
- package/dist/cjs/providers/replicate.d.cts +19 -0
- package/dist/cjs/providers/sanity.cjs +161 -0
- package/dist/cjs/providers/sanity.d.cts +38 -0
- package/dist/cjs/providers/sentry.cjs +47 -0
- package/dist/cjs/providers/sentry.d.cts +25 -0
- package/dist/cjs/providers/shared.cjs +49 -0
- package/dist/cjs/providers/shared.d.cts +14 -0
- package/dist/cjs/providers/shopify.cjs +40 -0
- package/dist/cjs/providers/shopify.d.cts +8 -0
- package/dist/cjs/providers/standard-webhooks-protocol.cjs +97 -0
- package/dist/cjs/providers/standard-webhooks-protocol.d.cts +14 -0
- package/dist/cjs/providers/standard-webhooks.cjs +15 -0
- package/dist/cjs/providers/standard-webhooks.d.cts +9 -0
- package/dist/cjs/providers/stripe.cjs +81 -0
- package/dist/cjs/providers/stripe.d.cts +7 -0
- package/dist/cjs/providers/svix.cjs +63 -0
- package/dist/cjs/providers/svix.d.cts +9 -0
- package/dist/cjs/providers/vercel.cjs +39 -0
- package/dist/cjs/providers/vercel.d.cts +15 -0
- package/dist/cjs/providers/workos.cjs +120 -0
- package/dist/cjs/providers/workos.d.cts +32 -0
- package/dist/cjs/types.cjs +2 -0
- package/dist/cjs/types.d.cts +68 -0
- package/dist/cli/args.d.ts +86 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +358 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/filesystem.d.ts +15 -0
- package/dist/cli/filesystem.d.ts.map +1 -0
- package/dist/cli/filesystem.js +170 -0
- package/dist/cli/filesystem.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 +64 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/templates.d.ts +13 -0
- package/dist/cli/templates.d.ts.map +1 -0
- package/dist/cli/templates.js +297 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/core.d.ts +6 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +26 -0
- package/dist/core.js.map +1 -0
- package/dist/diagnostics/catalog.d.ts +20 -0
- package/dist/diagnostics/catalog.d.ts.map +1 -0
- package/dist/diagnostics/catalog.js +335 -0
- package/dist/diagnostics/catalog.js.map +1 -0
- package/dist/diagnostics/index.d.ts +6 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +88 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/diagnostics/types.d.ts +21 -0
- package/dist/diagnostics/types.d.ts.map +1 -0
- package/dist/diagnostics/types.js +2 -0
- package/dist/diagnostics/types.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +10 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/body.d.ts +3 -0
- package/dist/internal/body.d.ts.map +1 -0
- package/dist/internal/body.js +48 -0
- package/dist/internal/body.js.map +1 -0
- package/dist/internal/bytes.d.ts +5 -0
- package/dist/internal/bytes.d.ts.map +1 -0
- package/dist/internal/bytes.js +38 -0
- package/dist/internal/bytes.js.map +1 -0
- package/dist/internal/crypto.d.ts +4 -0
- package/dist/internal/crypto.d.ts.map +1 -0
- package/dist/internal/crypto.js +49 -0
- package/dist/internal/crypto.js.map +1 -0
- package/dist/internal/headers.d.ts +3 -0
- package/dist/internal/headers.d.ts.map +1 -0
- package/dist/internal/headers.js +70 -0
- package/dist/internal/headers.js.map +1 -0
- package/dist/internal/options.d.ts +8 -0
- package/dist/internal/options.d.ts.map +1 -0
- package/dist/internal/options.js +128 -0
- package/dist/internal/options.js.map +1 -0
- package/dist/internal/prepare.d.ts +5 -0
- package/dist/internal/prepare.d.ts.map +1 -0
- package/dist/internal/prepare.js +9 -0
- package/dist/internal/prepare.js.map +1 -0
- package/dist/internal/provider-options.d.ts +7 -0
- package/dist/internal/provider-options.d.ts.map +1 -0
- package/dist/internal/provider-options.js +69 -0
- package/dist/internal/provider-options.js.map +1 -0
- package/dist/internal/provider.d.ts +40 -0
- package/dist/internal/provider.d.ts.map +1 -0
- package/dist/internal/provider.js +2 -0
- package/dist/internal/provider.js.map +1 -0
- package/dist/internal/verification.d.ts +13 -0
- package/dist/internal/verification.d.ts.map +1 -0
- package/dist/internal/verification.js +66 -0
- package/dist/internal/verification.js.map +1 -0
- package/dist/node/adapters/cloudflare.d.ts +1 -0
- package/dist/node/adapters/cloudflare.js +3 -0
- package/dist/node/adapters/express.d.ts +1 -0
- package/dist/node/adapters/express.js +3 -0
- package/dist/node/adapters/hono.d.ts +1 -0
- package/dist/node/adapters/hono.js +3 -0
- package/dist/node/adapters/nextjs.d.ts +1 -0
- package/dist/node/adapters/nextjs.js +3 -0
- package/dist/node/diagnostics/index.d.ts +1 -0
- package/dist/node/diagnostics/index.js +3 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +6 -0
- package/dist/providers/clerk.d.ts +10 -0
- package/dist/providers/clerk.d.ts.map +1 -0
- package/dist/providers/clerk.js +13 -0
- package/dist/providers/clerk.js.map +1 -0
- package/dist/providers/dodo-payments.d.ts +21 -0
- package/dist/providers/dodo-payments.d.ts.map +1 -0
- package/dist/providers/dodo-payments.js +24 -0
- package/dist/providers/dodo-payments.js.map +1 -0
- package/dist/providers/doppler.d.ts +38 -0
- package/dist/providers/doppler.d.ts.map +1 -0
- package/dist/providers/doppler.js +69 -0
- package/dist/providers/doppler.js.map +1 -0
- package/dist/providers/fal.d.ts +14 -0
- package/dist/providers/fal.d.ts.map +1 -0
- package/dist/providers/fal.js +78 -0
- package/dist/providers/fal.js.map +1 -0
- package/dist/providers/github.d.ts +8 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +50 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/gitlab.d.ts +21 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +24 -0
- package/dist/providers/gitlab.js.map +1 -0
- package/dist/providers/grafana.d.ts +36 -0
- package/dist/providers/grafana.d.ts.map +1 -0
- package/dist/providers/grafana.js +178 -0
- package/dist/providers/grafana.js.map +1 -0
- package/dist/providers/index.d.ts +27 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +89 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/lemon-squeezy.d.ts +16 -0
- package/dist/providers/lemon-squeezy.d.ts.map +1 -0
- package/dist/providers/lemon-squeezy.js +34 -0
- package/dist/providers/lemon-squeezy.js.map +1 -0
- package/dist/providers/linear.d.ts +37 -0
- package/dist/providers/linear.d.ts.map +1 -0
- package/dist/providers/linear.js +56 -0
- package/dist/providers/linear.js.map +1 -0
- package/dist/providers/paddle.d.ts +15 -0
- package/dist/providers/paddle.d.ts.map +1 -0
- package/dist/providers/paddle.js +103 -0
- package/dist/providers/paddle.js.map +1 -0
- package/dist/providers/polar.d.ts +26 -0
- package/dist/providers/polar.d.ts.map +1 -0
- package/dist/providers/polar.js +78 -0
- package/dist/providers/polar.js.map +1 -0
- package/dist/providers/razorpay.d.ts +20 -0
- package/dist/providers/razorpay.d.ts.map +1 -0
- package/dist/providers/razorpay.js +41 -0
- package/dist/providers/razorpay.js.map +1 -0
- package/dist/providers/replicate.d.ts +20 -0
- package/dist/providers/replicate.d.ts.map +1 -0
- package/dist/providers/replicate.js +23 -0
- package/dist/providers/replicate.js.map +1 -0
- package/dist/providers/sanity.d.ts +39 -0
- package/dist/providers/sanity.d.ts.map +1 -0
- package/dist/providers/sanity.js +159 -0
- package/dist/providers/sanity.js.map +1 -0
- package/dist/providers/sentry.d.ts +26 -0
- package/dist/providers/sentry.d.ts.map +1 -0
- package/dist/providers/sentry.js +45 -0
- package/dist/providers/sentry.js.map +1 -0
- package/dist/providers/shared.d.ts +15 -0
- package/dist/providers/shared.d.ts.map +1 -0
- package/dist/providers/shared.js +40 -0
- package/dist/providers/shared.js.map +1 -0
- package/dist/providers/shopify.d.ts +9 -0
- package/dist/providers/shopify.d.ts.map +1 -0
- package/dist/providers/shopify.js +38 -0
- package/dist/providers/shopify.js.map +1 -0
- package/dist/providers/standard-webhooks-protocol.d.ts +15 -0
- package/dist/providers/standard-webhooks-protocol.d.ts.map +1 -0
- package/dist/providers/standard-webhooks-protocol.js +95 -0
- package/dist/providers/standard-webhooks-protocol.js.map +1 -0
- package/dist/providers/standard-webhooks.d.ts +10 -0
- package/dist/providers/standard-webhooks.d.ts.map +1 -0
- package/dist/providers/standard-webhooks.js +13 -0
- package/dist/providers/standard-webhooks.js.map +1 -0
- package/dist/providers/stripe.d.ts +8 -0
- package/dist/providers/stripe.d.ts.map +1 -0
- package/dist/providers/stripe.js +79 -0
- package/dist/providers/stripe.js.map +1 -0
- package/dist/providers/svix.d.ts +10 -0
- package/dist/providers/svix.d.ts.map +1 -0
- package/dist/providers/svix.js +61 -0
- package/dist/providers/svix.js.map +1 -0
- package/dist/providers/vercel.d.ts +16 -0
- package/dist/providers/vercel.d.ts.map +1 -0
- package/dist/providers/vercel.js +37 -0
- package/dist/providers/vercel.js.map +1 -0
- package/dist/providers/workos.d.ts +33 -0
- package/dist/providers/workos.d.ts.map +1 -0
- package/dist/providers/workos.js +118 -0
- package/dist/providers/workos.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +200 -4
package/dist/cli/args.js
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { SUPPORTED_PROVIDERS } from '../providers/index.js';
|
|
2
|
+
export const FRAMEWORKS = ['express', 'nextjs', 'hono', 'cloudflare'];
|
|
3
|
+
const DEFAULT_BODY_LIMIT = 1048576;
|
|
4
|
+
const DEFAULT_OUT = 'hooklatch';
|
|
5
|
+
const SECRET_ENV_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6
|
+
/** Grafana's own default signature header name, matching the provider factory. */
|
|
7
|
+
const DEFAULT_SIGNATURE_HEADER = 'x-grafana-alerting-signature';
|
|
8
|
+
/** RFC 9110 field-name token characters, matching the Grafana provider factory. */
|
|
9
|
+
const FIELD_NAME_TOKEN = /^[!#$%&'*+.^_`|~\dA-Za-z-]+$/;
|
|
10
|
+
/**
|
|
11
|
+
* Header names that configured Grafana fields must not replace. This is
|
|
12
|
+
* Hooklatch configuration policy, not a Grafana rule; it matches the Grafana
|
|
13
|
+
* provider factory exactly.
|
|
14
|
+
*/
|
|
15
|
+
const RESERVED_HEADER_NAMES = new Set([
|
|
16
|
+
'host',
|
|
17
|
+
'content-length',
|
|
18
|
+
'transfer-encoding',
|
|
19
|
+
'connection',
|
|
20
|
+
'upgrade',
|
|
21
|
+
'trailer',
|
|
22
|
+
'te',
|
|
23
|
+
'proxy-authorization',
|
|
24
|
+
'proxy-authenticate',
|
|
25
|
+
'authorization',
|
|
26
|
+
'cookie',
|
|
27
|
+
'set-cookie',
|
|
28
|
+
]);
|
|
29
|
+
const DEFAULT_SECRET_ENV = {
|
|
30
|
+
stripe: 'STRIPE_WEBHOOK_SECRET',
|
|
31
|
+
github: 'GITHUB_WEBHOOK_SECRET',
|
|
32
|
+
shopify: 'SHOPIFY_WEBHOOK_SECRET',
|
|
33
|
+
'standard-webhooks': 'STANDARD_WEBHOOKS_SECRET',
|
|
34
|
+
clerk: 'CLERK_WEBHOOK_SIGNING_SECRET',
|
|
35
|
+
svix: 'SVIX_WEBHOOK_SECRET',
|
|
36
|
+
razorpay: 'RAZORPAY_WEBHOOK_SECRET',
|
|
37
|
+
paddle: 'PADDLE_WEBHOOK_SECRET',
|
|
38
|
+
'lemon-squeezy': 'LEMON_SQUEEZY_WEBHOOK_SECRET',
|
|
39
|
+
'dodo-payments': 'DODO_WEBHOOK_SECRET',
|
|
40
|
+
gitlab: 'GITLAB_WEBHOOK_SECRET',
|
|
41
|
+
replicate: 'REPLICATE_WEBHOOK_SECRET',
|
|
42
|
+
workos: 'WORKOS_WEBHOOK_SECRET',
|
|
43
|
+
sentry: 'SENTRY_WEBHOOK_SECRET',
|
|
44
|
+
doppler: 'DOPPLER_WEBHOOK_SECRET',
|
|
45
|
+
sanity: 'SANITY_WEBHOOK_SECRET',
|
|
46
|
+
grafana: 'GRAFANA_WEBHOOK_SECRET',
|
|
47
|
+
polar: 'POLAR_WEBHOOK_SECRET',
|
|
48
|
+
linear: 'LINEAR_WEBHOOK_SECRET',
|
|
49
|
+
vercel: 'VERCEL_WEBHOOK_SECRET',
|
|
50
|
+
};
|
|
51
|
+
export const HELP_TEXT = `Usage: hooklatch init webhook --provider <id> --framework <id> [options]
|
|
52
|
+
|
|
53
|
+
Generate one TypeScript webhook endpoint file from an existing Hooklatch adapter.
|
|
54
|
+
|
|
55
|
+
Required:
|
|
56
|
+
--provider <id> Implemented provider id.
|
|
57
|
+
--framework <id> One of: express, nextjs, hono, cloudflare.
|
|
58
|
+
|
|
59
|
+
Options:
|
|
60
|
+
--out <dir> Output directory (default: ${DEFAULT_OUT}).
|
|
61
|
+
--secret-env <NAME> Environment variable holding the secret (default by provider).
|
|
62
|
+
--body-limit <bytes> Positive safe integer body limit (default: ${DEFAULT_BODY_LIMIT}).
|
|
63
|
+
--grafana-mode <mode> Grafana only: body or timestamped (required for grafana).
|
|
64
|
+
--signature-header <NAME>
|
|
65
|
+
Grafana only: RFC 9110 header token (default ${DEFAULT_SIGNATURE_HEADER}).
|
|
66
|
+
--timestamp-header <NAME>
|
|
67
|
+
Grafana only: required with timestamped; forbidden with body.
|
|
68
|
+
--polar-secret-mode <mode>
|
|
69
|
+
Polar only: current (default) or legacy.
|
|
70
|
+
--public-key-env <NAME>
|
|
71
|
+
Fal only: env var holding comma-separated Base64url public keys (default FAL_WEBHOOK_PUBLIC_KEYS).
|
|
72
|
+
--expected-user-env <NAME>
|
|
73
|
+
Fal only: env var holding the expected user id (default FAL_WEBHOOK_USER_ID).
|
|
74
|
+
--dry-run Print the target path and contents without writing.
|
|
75
|
+
-h, --help Show this help.
|
|
76
|
+
|
|
77
|
+
Exit codes:
|
|
78
|
+
0 Success, dry run, or help.
|
|
79
|
+
1 Unexpected generation or I/O error.
|
|
80
|
+
2 Invalid arguments or unsafe path.
|
|
81
|
+
3 Target file already exists.
|
|
82
|
+
`;
|
|
83
|
+
function isFramework(value) {
|
|
84
|
+
// SAFETY: FRAMEWORKS is a fixed readonly tuple of literal framework names; widening to string[] only supports Array.includes.
|
|
85
|
+
return FRAMEWORKS.includes(value);
|
|
86
|
+
}
|
|
87
|
+
// CLI accepted providers come solely from SUPPORTED_PROVIDERS (Codex-owned registry).
|
|
88
|
+
// Shadow registration of 'vercel'/'fal' is intentionally removed: those providers
|
|
89
|
+
// are not registered at this base and cannot honestly be scaffolded through the CLI.
|
|
90
|
+
function isProvider(value) {
|
|
91
|
+
// SAFETY: SUPPORTED_PROVIDERS is a fixed readonly tuple of implemented provider ids; widening to string[] only supports Array.includes.
|
|
92
|
+
return SUPPORTED_PROVIDERS.includes(value);
|
|
93
|
+
}
|
|
94
|
+
function isPositiveSafeInteger(value) {
|
|
95
|
+
if (!/^[0-9]+$/.test(value))
|
|
96
|
+
return false;
|
|
97
|
+
const number = Number(value);
|
|
98
|
+
return Number.isSafeInteger(number) && number > 0;
|
|
99
|
+
}
|
|
100
|
+
function optionsError(message) {
|
|
101
|
+
return { kind: 'error', message };
|
|
102
|
+
}
|
|
103
|
+
/** A nonempty RFC 9110 field-name token that is not reserved by Hooklatch policy. */
|
|
104
|
+
function isConfiguredHeaderName(value) {
|
|
105
|
+
return FIELD_NAME_TOKEN.test(value) && !RESERVED_HEADER_NAMES.has(value.toLowerCase());
|
|
106
|
+
}
|
|
107
|
+
function firstGrafanaFlag(flags) {
|
|
108
|
+
if (flags.grafanaMode !== undefined)
|
|
109
|
+
return '--grafana-mode';
|
|
110
|
+
if (flags.signatureHeader !== undefined)
|
|
111
|
+
return '--signature-header';
|
|
112
|
+
if (flags.timestampHeader !== undefined)
|
|
113
|
+
return '--timestamp-header';
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
function buildGrafanaOptions(flags) {
|
|
117
|
+
if (flags.polarSecretMode !== undefined) {
|
|
118
|
+
return optionsError('The --polar-secret-mode flag is only valid for polar.');
|
|
119
|
+
}
|
|
120
|
+
const mode = flags.grafanaMode;
|
|
121
|
+
if (mode === undefined)
|
|
122
|
+
return optionsError('Missing required --grafana-mode for grafana.');
|
|
123
|
+
if (mode !== 'body' && mode !== 'timestamped') {
|
|
124
|
+
return optionsError('Invalid --grafana-mode: expected body or timestamped.');
|
|
125
|
+
}
|
|
126
|
+
if (flags.signatureHeader !== undefined && !isConfiguredHeaderName(flags.signatureHeader)) {
|
|
127
|
+
return optionsError('Invalid --signature-header: expected an RFC 9110 field-name token that is not reserved.');
|
|
128
|
+
}
|
|
129
|
+
if (mode === 'body') {
|
|
130
|
+
if (flags.timestampHeader !== undefined) {
|
|
131
|
+
return optionsError('The --timestamp-header flag is not allowed in Grafana body mode.');
|
|
132
|
+
}
|
|
133
|
+
if (flags.signatureHeader === undefined) {
|
|
134
|
+
return { kind: 'options', options: { provider: 'grafana', options: { mode: 'body' } } };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
kind: 'options',
|
|
138
|
+
options: { provider: 'grafana', options: { mode: 'body', signatureHeader: flags.signatureHeader } },
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const timestampHeader = flags.timestampHeader;
|
|
142
|
+
if (timestampHeader === undefined) {
|
|
143
|
+
return optionsError('Missing required --timestamp-header for Grafana timestamped mode.');
|
|
144
|
+
}
|
|
145
|
+
if (!isConfiguredHeaderName(timestampHeader)) {
|
|
146
|
+
return optionsError('Invalid --timestamp-header: expected an RFC 9110 field-name token that is not reserved.');
|
|
147
|
+
}
|
|
148
|
+
const signatureHeader = flags.signatureHeader;
|
|
149
|
+
const effectiveSignatureHeader = signatureHeader === undefined ? DEFAULT_SIGNATURE_HEADER : signatureHeader;
|
|
150
|
+
if (effectiveSignatureHeader.toLowerCase() === timestampHeader.toLowerCase()) {
|
|
151
|
+
return optionsError('The Grafana signature and timestamp headers must differ (case-insensitive).');
|
|
152
|
+
}
|
|
153
|
+
if (signatureHeader === undefined) {
|
|
154
|
+
return {
|
|
155
|
+
kind: 'options',
|
|
156
|
+
options: { provider: 'grafana', options: { mode: 'timestamped', timestampHeader } },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
kind: 'options',
|
|
161
|
+
options: { provider: 'grafana', options: { mode: 'timestamped', signatureHeader, timestampHeader } },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function buildFalOptions(flags) {
|
|
165
|
+
if (flags.grafanaMode !== undefined || flags.signatureHeader !== undefined || flags.timestampHeader !== undefined) {
|
|
166
|
+
return optionsError('The --grafana-mode, --signature-header and --timestamp-header flags are only valid for grafana.');
|
|
167
|
+
}
|
|
168
|
+
if (flags.polarSecretMode !== undefined) {
|
|
169
|
+
return optionsError('The --polar-secret-mode flag is only valid for polar.');
|
|
170
|
+
}
|
|
171
|
+
const publicKeyEnv = flags.publicKeyEnv ?? 'FAL_WEBHOOK_PUBLIC_KEYS';
|
|
172
|
+
const expectedUserEnv = flags.expectedUserEnv ?? 'FAL_WEBHOOK_USER_ID';
|
|
173
|
+
if (!SECRET_ENV_PATTERN.test(publicKeyEnv)) {
|
|
174
|
+
return optionsError('Invalid --public-key-env: expected an identifier.');
|
|
175
|
+
}
|
|
176
|
+
if (!SECRET_ENV_PATTERN.test(expectedUserEnv)) {
|
|
177
|
+
return optionsError('Invalid --expected-user-env: expected an identifier.');
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
kind: 'options',
|
|
181
|
+
options: {
|
|
182
|
+
provider: 'fal',
|
|
183
|
+
options: { publicKeyEnv, expectedUserEnv },
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function buildPolarOptions(flags) {
|
|
188
|
+
const grafanaFlag = firstGrafanaFlag(flags);
|
|
189
|
+
if (grafanaFlag !== null)
|
|
190
|
+
return optionsError(`The ${grafanaFlag} flag is only valid for grafana.`);
|
|
191
|
+
const mode = flags.polarSecretMode;
|
|
192
|
+
if (mode === undefined) {
|
|
193
|
+
return { kind: 'options', options: { provider: 'polar', options: { secretMode: 'current' } } };
|
|
194
|
+
}
|
|
195
|
+
if (mode !== 'current' && mode !== 'legacy') {
|
|
196
|
+
return optionsError('Invalid --polar-secret-mode: expected current or legacy.');
|
|
197
|
+
}
|
|
198
|
+
return { kind: 'options', options: { provider: 'polar', options: { secretMode: mode } } };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Apply provider-specific flag rules. Registration stays coordinator-owned:
|
|
202
|
+
* a provider that is not yet in the public registry is rejected by
|
|
203
|
+
* `parseArgs` before this function runs.
|
|
204
|
+
*/
|
|
205
|
+
export function buildProviderCliOptions(provider, flags) {
|
|
206
|
+
if (provider === 'grafana')
|
|
207
|
+
return buildGrafanaOptions(flags);
|
|
208
|
+
if (provider === 'polar')
|
|
209
|
+
return buildPolarOptions(flags);
|
|
210
|
+
if (provider === 'fal')
|
|
211
|
+
return buildFalOptions(flags);
|
|
212
|
+
const grafanaFlag = firstGrafanaFlag(flags);
|
|
213
|
+
if (grafanaFlag !== null)
|
|
214
|
+
return optionsError(`The ${grafanaFlag} flag is only valid for grafana.`);
|
|
215
|
+
if (flags.polarSecretMode !== undefined) {
|
|
216
|
+
return optionsError('The --polar-secret-mode flag is only valid for polar.');
|
|
217
|
+
}
|
|
218
|
+
if (flags.publicKeyEnv !== undefined || flags.expectedUserEnv !== undefined) {
|
|
219
|
+
return optionsError('The --public-key-env and --expected-user-env flags are only valid for fal.');
|
|
220
|
+
}
|
|
221
|
+
return { kind: 'none' };
|
|
222
|
+
}
|
|
223
|
+
export function parseArgs(argv) {
|
|
224
|
+
if (argv.length === 0)
|
|
225
|
+
return { kind: 'help' };
|
|
226
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
227
|
+
// Help is allowed only as a standalone/global request.
|
|
228
|
+
if (argv.length === 1)
|
|
229
|
+
return { kind: 'help' };
|
|
230
|
+
// Allow "init webhook --help" specifically.
|
|
231
|
+
if (argv[0] === 'init' && argv[1] === 'webhook' && argv.length === 3 && (argv[2] === '--help' || argv[2] === '-h')) {
|
|
232
|
+
return { kind: 'help' };
|
|
233
|
+
}
|
|
234
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid arguments.' };
|
|
235
|
+
}
|
|
236
|
+
if (argv[0] !== 'init' || argv[1] !== 'webhook') {
|
|
237
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid command. Use: hooklatch init webhook ...' };
|
|
238
|
+
}
|
|
239
|
+
const rest = argv.slice(2);
|
|
240
|
+
const seen = new Set();
|
|
241
|
+
let provider;
|
|
242
|
+
let framework;
|
|
243
|
+
let out = DEFAULT_OUT;
|
|
244
|
+
let secretEnv;
|
|
245
|
+
let bodyLimit = DEFAULT_BODY_LIMIT;
|
|
246
|
+
let dryRun = false;
|
|
247
|
+
let grafanaMode;
|
|
248
|
+
let signatureHeader;
|
|
249
|
+
let timestampHeader;
|
|
250
|
+
let polarSecretMode;
|
|
251
|
+
let publicKeyEnv;
|
|
252
|
+
let expectedUserEnv;
|
|
253
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
254
|
+
const flag = rest[i];
|
|
255
|
+
if (flag === '--dry-run') {
|
|
256
|
+
if (seen.has(flag))
|
|
257
|
+
return { kind: 'error', exitCode: 2, message: 'Duplicate flag: --dry-run.' };
|
|
258
|
+
seen.add(flag);
|
|
259
|
+
dryRun = true;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (flag === '--provider' || flag === '--framework' || flag === '--out' || flag === '--secret-env' || flag === '--body-limit'
|
|
263
|
+
|| flag === '--grafana-mode' || flag === '--signature-header' || flag === '--timestamp-header' || flag === '--polar-secret-mode'
|
|
264
|
+
|| flag === '--public-key-env' || flag === '--expected-user-env') {
|
|
265
|
+
if (seen.has(flag))
|
|
266
|
+
return { kind: 'error', exitCode: 2, message: `Duplicate flag: ${flag}.` };
|
|
267
|
+
seen.add(flag);
|
|
268
|
+
const value = rest[i + 1];
|
|
269
|
+
if (value === undefined || value.startsWith('--') || value === '-h') {
|
|
270
|
+
return { kind: 'error', exitCode: 2, message: `Missing value for ${flag}.` };
|
|
271
|
+
}
|
|
272
|
+
i += 1;
|
|
273
|
+
if (flag === '--provider')
|
|
274
|
+
provider = value;
|
|
275
|
+
else if (flag === '--framework')
|
|
276
|
+
framework = value;
|
|
277
|
+
else if (flag === '--out')
|
|
278
|
+
out = value;
|
|
279
|
+
else if (flag === '--secret-env')
|
|
280
|
+
secretEnv = value;
|
|
281
|
+
else if (flag === '--grafana-mode')
|
|
282
|
+
grafanaMode = value;
|
|
283
|
+
else if (flag === '--signature-header')
|
|
284
|
+
signatureHeader = value;
|
|
285
|
+
else if (flag === '--timestamp-header')
|
|
286
|
+
timestampHeader = value;
|
|
287
|
+
else if (flag === '--polar-secret-mode')
|
|
288
|
+
polarSecretMode = value;
|
|
289
|
+
else if (flag === '--public-key-env')
|
|
290
|
+
publicKeyEnv = value;
|
|
291
|
+
else if (flag === '--expected-user-env')
|
|
292
|
+
expectedUserEnv = value;
|
|
293
|
+
else if (flag === '--body-limit') {
|
|
294
|
+
if (!isPositiveSafeInteger(value)) {
|
|
295
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid --body-limit: expected a positive safe integer.' };
|
|
296
|
+
}
|
|
297
|
+
bodyLimit = Number(value);
|
|
298
|
+
}
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
return { kind: 'error', exitCode: 2, message: 'Unknown flag.' };
|
|
302
|
+
}
|
|
303
|
+
if (!provider)
|
|
304
|
+
return { kind: 'error', exitCode: 2, message: 'Missing required --provider.' };
|
|
305
|
+
if (!framework)
|
|
306
|
+
return { kind: 'error', exitCode: 2, message: 'Missing required --framework.' };
|
|
307
|
+
if (!isProvider(provider)) {
|
|
308
|
+
return { kind: 'error', exitCode: 2, message: 'Unsupported provider.' };
|
|
309
|
+
}
|
|
310
|
+
if (!isFramework(framework)) {
|
|
311
|
+
return { kind: 'error', exitCode: 2, message: 'Unsupported framework.' };
|
|
312
|
+
}
|
|
313
|
+
if (out.length === 0)
|
|
314
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid --out: empty path.' };
|
|
315
|
+
// grafana/polar and existing HMAC providers.
|
|
316
|
+
const providerOptionsResult = buildProviderCliOptions(provider, {
|
|
317
|
+
grafanaMode,
|
|
318
|
+
signatureHeader,
|
|
319
|
+
timestampHeader,
|
|
320
|
+
polarSecretMode,
|
|
321
|
+
publicKeyEnv,
|
|
322
|
+
expectedUserEnv,
|
|
323
|
+
});
|
|
324
|
+
if (providerOptionsResult.kind === 'error') {
|
|
325
|
+
return { kind: 'error', exitCode: 2, message: providerOptionsResult.message };
|
|
326
|
+
}
|
|
327
|
+
if (provider === 'fal') {
|
|
328
|
+
if (secretEnv !== undefined) {
|
|
329
|
+
return { kind: 'error', exitCode: 2, message: 'The --secret-env flag is not valid for fal.' };
|
|
330
|
+
}
|
|
331
|
+
if (providerOptionsResult.kind !== 'options' || providerOptionsResult.options.provider !== 'fal') {
|
|
332
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid fal credential configuration.' };
|
|
333
|
+
}
|
|
334
|
+
return { kind: 'command', command: { provider, framework, out, bodyLimit, dryRun,
|
|
335
|
+
publicKeyEnv: providerOptionsResult.options.options.publicKeyEnv,
|
|
336
|
+
expectedUserEnv: providerOptionsResult.options.options.expectedUserEnv } };
|
|
337
|
+
}
|
|
338
|
+
const resolvedSecretEnv = secretEnv ?? DEFAULT_SECRET_ENV[provider];
|
|
339
|
+
if (!SECRET_ENV_PATTERN.test(resolvedSecretEnv)) {
|
|
340
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid --secret-env: expected an identifier.' };
|
|
341
|
+
}
|
|
342
|
+
const baseCommand = {
|
|
343
|
+
provider,
|
|
344
|
+
framework,
|
|
345
|
+
out,
|
|
346
|
+
secretEnv: resolvedSecretEnv,
|
|
347
|
+
bodyLimit,
|
|
348
|
+
dryRun,
|
|
349
|
+
};
|
|
350
|
+
if (providerOptionsResult.kind === 'none') {
|
|
351
|
+
return { kind: 'command', command: baseCommand };
|
|
352
|
+
}
|
|
353
|
+
const configured = providerOptionsResult.options;
|
|
354
|
+
if (configured.provider === 'fal')
|
|
355
|
+
return { kind: 'error', exitCode: 2, message: 'Invalid HMAC credential configuration.' };
|
|
356
|
+
return { kind: 'command', command: { ...baseCommand, providerOptions: configured } };
|
|
357
|
+
}
|
|
358
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class CliError extends Error {
|
|
2
|
+
readonly exitCode: number;
|
|
3
|
+
constructor(exitCode: number, message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function validateOutDir(input: string): string[];
|
|
6
|
+
export declare function targetFileName(provider: string, framework: string): string;
|
|
7
|
+
interface ResolvedOutput {
|
|
8
|
+
readonly relativePath: string;
|
|
9
|
+
readonly absolutePath: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function resolveOutput(cwd: string, outDir: string, fileName: string): ResolvedOutput;
|
|
12
|
+
export declare function ensureParentDirectories(cwd: string, absoluteFilePath: string): void;
|
|
13
|
+
export declare function writeFileExclusive(filePath: string, content: string): void;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/cli/filesystem.ts"],"names":[],"mappings":"AAGA,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK9C;AA+CD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAatD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS1E;AAED,UAAU,cAAc;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAmD3F;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAoBnF;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAwB1E"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export class CliError extends Error {
|
|
4
|
+
exitCode;
|
|
5
|
+
constructor(exitCode, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'CliError';
|
|
8
|
+
this.exitCode = exitCode;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Narrow an unknown thrown value to a Node error with an errno `code`. */
|
|
12
|
+
function isErrnoException(error) {
|
|
13
|
+
return typeof error === 'object' && error !== null && 'code' in error && typeof error.code === 'string';
|
|
14
|
+
}
|
|
15
|
+
function rejectUnsafeSegment(segment) {
|
|
16
|
+
if (segment === '' || segment === '.' || segment === '..') {
|
|
17
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
18
|
+
}
|
|
19
|
+
if (segment.toLowerCase() === '.git' || segment.toLowerCase() === 'node_modules') {
|
|
20
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
21
|
+
}
|
|
22
|
+
if (/[<>:"|?*]/.test(segment) || [...segment].some((character) => character.charCodeAt(0) < 32)
|
|
23
|
+
|| /[. ]$/.test(segment)) {
|
|
24
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
25
|
+
}
|
|
26
|
+
// Windows reserved device names.
|
|
27
|
+
if (/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(segment)) {
|
|
28
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function inspectPath(target) {
|
|
32
|
+
try {
|
|
33
|
+
return fs.lstatSync(target);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (isErrnoException(error) && error.code === 'ENOENT')
|
|
37
|
+
return undefined;
|
|
38
|
+
throw new CliError(1, 'Unable to inspect output path.');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function splitPath(input) {
|
|
42
|
+
const normalized = input.replace(/\\/g, '/');
|
|
43
|
+
const trimmed = normalized.replace(/\/+$/, '');
|
|
44
|
+
if (trimmed.length === 0)
|
|
45
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
46
|
+
const segments = trimmed.split('/');
|
|
47
|
+
for (const segment of segments)
|
|
48
|
+
rejectUnsafeSegment(segment);
|
|
49
|
+
return segments;
|
|
50
|
+
}
|
|
51
|
+
export function validateOutDir(input) {
|
|
52
|
+
if (input.length === 0) {
|
|
53
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
54
|
+
}
|
|
55
|
+
if (input.includes('\0'))
|
|
56
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
57
|
+
const normalized = input.replace(/\\/g, '/');
|
|
58
|
+
if (path.isAbsolute(input) || /^[a-zA-Z]:/.test(input) || normalized.startsWith('//')) {
|
|
59
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
60
|
+
}
|
|
61
|
+
return splitPath(input);
|
|
62
|
+
}
|
|
63
|
+
export function targetFileName(provider, framework) {
|
|
64
|
+
if (framework === 'nextjs')
|
|
65
|
+
return 'route.ts';
|
|
66
|
+
if (framework === 'cloudflare')
|
|
67
|
+
return `${provider}.cloudflare.ts`;
|
|
68
|
+
if (framework === 'hono')
|
|
69
|
+
return `${provider}.hono.ts`;
|
|
70
|
+
if (framework === 'express')
|
|
71
|
+
return `${provider}.express.ts`;
|
|
72
|
+
throw new CliError(2, 'Unsupported framework.');
|
|
73
|
+
}
|
|
74
|
+
export function resolveOutput(cwd, outDir, fileName) {
|
|
75
|
+
const outSegments = validateOutDir(outDir);
|
|
76
|
+
const fileSegments = [fileName];
|
|
77
|
+
// validate file name segments too (no traversal)
|
|
78
|
+
for (const segment of fileSegments) {
|
|
79
|
+
if (segment.includes('/') || segment.includes('\\') || segment.includes('\0')) {
|
|
80
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
81
|
+
}
|
|
82
|
+
if (segment === '..' || segment === '.' || segment === '')
|
|
83
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
84
|
+
}
|
|
85
|
+
const relativeSegments = [...outSegments, ...fileSegments];
|
|
86
|
+
const absolutePath = path.resolve(cwd, ...relativeSegments);
|
|
87
|
+
const relativePath = relativeSegments.join('/');
|
|
88
|
+
const relativeFromCwd = path.relative(cwd, absolutePath);
|
|
89
|
+
if (relativeFromCwd === '' || relativeFromCwd === '..'
|
|
90
|
+
|| relativeFromCwd.startsWith(`..${path.sep}`) || path.isAbsolute(relativeFromCwd)) {
|
|
91
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
92
|
+
}
|
|
93
|
+
// Check existing ancestors for symlinks/junctions/non-directories.
|
|
94
|
+
let current = cwd;
|
|
95
|
+
const ancestorSegments = relativeSegments.slice(0, -1);
|
|
96
|
+
for (const segment of ancestorSegments) {
|
|
97
|
+
current = path.join(current, segment);
|
|
98
|
+
const stat = inspectPath(current);
|
|
99
|
+
if (stat !== undefined) {
|
|
100
|
+
if (stat.isSymbolicLink())
|
|
101
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
102
|
+
if (!stat.isDirectory())
|
|
103
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Existing target.
|
|
107
|
+
const targetStat = inspectPath(absolutePath);
|
|
108
|
+
if (targetStat !== undefined) {
|
|
109
|
+
if (targetStat.isSymbolicLink())
|
|
110
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
111
|
+
throw new CliError(3, 'Target file already exists.');
|
|
112
|
+
}
|
|
113
|
+
return { relativePath, absolutePath };
|
|
114
|
+
}
|
|
115
|
+
export function ensureParentDirectories(cwd, absoluteFilePath) {
|
|
116
|
+
const dir = path.dirname(absoluteFilePath);
|
|
117
|
+
const relative = path.relative(cwd, dir);
|
|
118
|
+
const segments = relative === '' ? [] : relative.split(path.sep);
|
|
119
|
+
let current = cwd;
|
|
120
|
+
for (const segment of segments) {
|
|
121
|
+
current = path.join(current, segment);
|
|
122
|
+
const stat = inspectPath(current);
|
|
123
|
+
if (stat !== undefined) {
|
|
124
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
125
|
+
throw new CliError(2, 'Unsafe output path.');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
try {
|
|
130
|
+
fs.mkdirSync(current);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
throw new CliError(1, 'Unable to create output directory.');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export function writeFileExclusive(filePath, content) {
|
|
139
|
+
let fd;
|
|
140
|
+
try {
|
|
141
|
+
fd = fs.openSync(filePath, 'wx');
|
|
142
|
+
fs.writeFileSync(fd, content, 'utf8');
|
|
143
|
+
try {
|
|
144
|
+
fs.fsyncSync(fd);
|
|
145
|
+
}
|
|
146
|
+
catch { /* best effort */ }
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (fd !== undefined) {
|
|
150
|
+
// Operate on our descriptor, never unlink a path another creator may replace.
|
|
151
|
+
try {
|
|
152
|
+
fs.ftruncateSync(fd, 0);
|
|
153
|
+
}
|
|
154
|
+
catch { /* A partial owned file may remain. */ }
|
|
155
|
+
}
|
|
156
|
+
if (isErrnoException(error) && error.code === 'EEXIST') {
|
|
157
|
+
throw new CliError(3, 'Target file already exists.');
|
|
158
|
+
}
|
|
159
|
+
throw new CliError(1, 'Unable to write output file.');
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
if (fd !== undefined) {
|
|
163
|
+
try {
|
|
164
|
+
fs.closeSync(fd);
|
|
165
|
+
}
|
|
166
|
+
catch { /* ignore */ }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=filesystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/cli/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs, HELP_TEXT } from './args.js';
|
|
3
|
+
import { renderTemplate } from './templates.js';
|
|
4
|
+
import { resolveOutput, targetFileName, ensureParentDirectories, writeFileExclusive, CliError } from './filesystem.js';
|
|
5
|
+
function main() {
|
|
6
|
+
const result = parseArgs(process.argv.slice(2));
|
|
7
|
+
if (result.kind === 'help') {
|
|
8
|
+
process.stdout.write(HELP_TEXT);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (result.kind === 'error') {
|
|
12
|
+
process.stderr.write(`${result.message}\n`);
|
|
13
|
+
process.exitCode = result.exitCode;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const command = result.command;
|
|
17
|
+
const fileName = targetFileName(command.provider, command.framework);
|
|
18
|
+
let resolved;
|
|
19
|
+
try {
|
|
20
|
+
resolved = resolveOutput(process.cwd(), command.out, fileName);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const message = error instanceof CliError ? error.message : 'Unable to inspect output path.';
|
|
24
|
+
const exitCode = error instanceof CliError ? error.exitCode : 2;
|
|
25
|
+
process.stderr.write(`${message}\n`);
|
|
26
|
+
process.exitCode = exitCode;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let templateOptions;
|
|
30
|
+
if (command.provider === 'fal') {
|
|
31
|
+
templateOptions = { publicKeyEnv: command.publicKeyEnv, expectedUserEnv: command.expectedUserEnv,
|
|
32
|
+
bodyLimit: command.bodyLimit };
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
templateOptions = command.providerOptions === undefined
|
|
36
|
+
? { secretEnv: command.secretEnv, bodyLimit: command.bodyLimit }
|
|
37
|
+
: { secretEnv: command.secretEnv, bodyLimit: command.bodyLimit, providerOptions: command.providerOptions };
|
|
38
|
+
}
|
|
39
|
+
const content = renderTemplate(command.provider, command.framework, templateOptions);
|
|
40
|
+
if (command.dryRun) {
|
|
41
|
+
process.stdout.write(`${resolved.relativePath}\n${content}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
ensureParentDirectories(process.cwd(), resolved.absolutePath);
|
|
46
|
+
writeFileExclusive(resolved.absolutePath, content);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const message = error instanceof CliError ? error.message : 'Unable to write output file.';
|
|
50
|
+
const exitCode = error instanceof CliError ? error.exitCode : 1;
|
|
51
|
+
process.stderr.write(`${message}\n`);
|
|
52
|
+
process.exitCode = exitCode;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
process.stdout.write(`Created ${resolved.relativePath}\n`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
main();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
process.stderr.write('Unexpected error.\n');
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=index.js.map
|