@stacksjs/env 0.74.69 → 0.74.70

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/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './runtime';
2
2
  export * from './deployment';
3
+ export * from './integrations';
3
4
  export * from './types';
4
5
  export * from './crypto';
5
6
  export * from './parser';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./runtime";export*from"./deployment";export*from"./types";export*from"./crypto";export*from"./parser";export*from"./plugin";export*from"./cli";export*from"./plaintext";export*from"./tenants";export*from"./utils";
1
+ export*from"./runtime";export*from"./deployment";export*from"./integrations";export*from"./types";export*from"./crypto";export*from"./parser";export*from"./plugin";export*from"./cli";export*from"./plaintext";export*from"./tenants";export*from"./utils";
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Fold the spellings that mean the same deployment onto one name, so an
3
+ * allowlist of `['prod']` admits `APP_ENV=production` and the reverse.
4
+ *
5
+ * Only these three aliases, and only exact matches. `local`, `development` and
6
+ * `test` are deliberately **not** folded together: they are three different
7
+ * places with three different reasons to be excluded, and a framework that
8
+ * quietly treated them as one would make "allow my machine" also mean "allow
9
+ * CI". `@stacksjs/env`'s own loader normalizes the same three aliases when it
10
+ * picks an `.env` file to read.
11
+ */
12
+ export declare function normalizeEnvironmentName(value: string | undefined | null): string | undefined;
13
+ /**
14
+ * The environment an integration should gate on, or `undefined` when nothing
15
+ * declared one.
16
+ *
17
+ * Read at call time rather than at import: `APP_ENV` is routinely set after the
18
+ * module graph loads - a test harness pinning it, a CLI resolving `--env` - and
19
+ * a const would freeze whatever happened to be set first (stacksjs/stacks#2581).
20
+ *
21
+ * Unlike `appEnv()`, which answers `local` so callers always have a string, this
22
+ * answers `undefined`. The difference matters here: an unset or unreadable
23
+ * `APP_ENV` must not be *guessed* into a label that an allowlist might admit.
24
+ */
25
+ export declare function integrationEnvironment(): string | undefined;
26
+ /**
27
+ * Decide whether an integration may initialize in this process.
28
+ *
29
+ * Same answer in a web or API server, the dashboard, a worker and a CLI
30
+ * command, because all of them read the same `APP_ENV`.
31
+ *
32
+ * @param options the integration's own configuration
33
+ * @param defaultEnvironments the allowlist to use when the app did not set one
34
+ */
35
+ export declare function integrationGate(options: EnvironmentGatedIntegration | undefined | null, defaultEnvironments?: readonly string[]): IntegrationGate;
36
+ /**
37
+ * One environment gate, shared by every integration that talks to a remote
38
+ * service (stacksjs/stacks#2792).
39
+ *
40
+ * The problem it solves is not labelling. An adapter that attaches
41
+ * unconditionally and tags its events `development` still transmits them, so a
42
+ * laptop and a CI run report into the same project as production and a local
43
+ * startup failure reads as a live incident. The label describes the event; it
44
+ * does not stop it leaving.
45
+ *
46
+ * So the gate is evaluated *before* an adapter initializes. A gate that answers
47
+ * `false` means no upload client, no remote capture hook, no injected tracking
48
+ * script, no flush timer and no request - not "send it marked local". Ordinary
49
+ * console and file logging are unaffected: they are not this gate's business.
50
+ *
51
+ * The configuration surface is deliberately one option:
52
+ *
53
+ * ```ts
54
+ * bughq: {
55
+ * key: env.BUGHQ_KEY,
56
+ * environments: ['production', 'staging'],
57
+ * }
58
+ * ```
59
+ *
60
+ * There is no sibling `environment` field and no `enabledIn`. An application
61
+ * never repeats `env.APP_ENV` in each integration: the effective value is
62
+ * resolved here once, used to check the allowlist, and handed back on
63
+ * {@link IntegrationGate.environment} so the adapter can attach it as event
64
+ * metadata without asking.
65
+ *
66
+ * **`APP_ENV` is a configuration label, not proof of deployment identity.** A
67
+ * command launched locally with `APP_ENV=production` passes a production
68
+ * allowlist, because nothing here can tell the difference. Treat the allowlist
69
+ * as "which labels may transmit", not as an authorization boundary.
70
+ */
71
+ /**
72
+ * The default allowlist for a remote-telemetry integration.
73
+ *
74
+ * Deployed environments report; a developer's machine, CI and test runs do not,
75
+ * until someone adds their label. New integrations should adopt this rather than
76
+ * inventing a policy, and an existing installation's behaviour should not be
77
+ * changed silently by picking it up.
78
+ */
79
+ export declare const REMOTE_TELEMETRY_ENVIRONMENTS: readonly string[];
80
+ /** The environment-gating surface an integration's own options extend. */
81
+ export declare interface EnvironmentGatedIntegration {
82
+ enabled?: boolean
83
+ environments?: readonly string[]
84
+ }
85
+ export declare interface IntegrationGate {
86
+ enabled: boolean
87
+ environment: string | undefined
88
+ reason: IntegrationGateReason
89
+ }
90
+ /** Why the gate answered as it did. Worth logging; worth asserting in tests. */
91
+ export type IntegrationGateReason = | 'disabled-explicitly'
92
+ | 'empty-allowlist'
93
+ | 'environment-unknown'
94
+ | 'environment-excluded'
95
+ | 'environment-allowed';
@@ -0,0 +1 @@
1
+ export const REMOTE_TELEMETRY_ENVIRONMENTS=["production","staging"];export function normalizeEnvironmentName(value){if(typeof value!=="string")return;const normalized=value.trim().toLowerCase();if(!/^[a-z0-9_-]+$/.test(normalized))return;if(normalized==="prod")return"production";if(normalized==="stage")return"staging";if(normalized==="dev")return"development";return normalized}export function integrationEnvironment(){return normalizeEnvironmentName(process.env.APP_ENV)??normalizeEnvironmentName("development")}export function integrationGate(options,defaultEnvironments=REMOTE_TELEMETRY_ENVIRONMENTS){const environment=integrationEnvironment();if(options?.enabled===!1)return{enabled:!1,environment,reason:"disabled-explicitly"};const allowlist=options?.environments??defaultEnvironments;if(allowlist.length===0)return{enabled:!1,environment,reason:"empty-allowlist"};if(environment===void 0)return{enabled:!1,environment,reason:"environment-unknown"};const permitted=new Set;for(const entry of allowlist){const name=normalizeEnvironmentName(entry);if(name!==void 0)permitted.add(name)}return permitted.has(environment)?{enabled:!0,environment,reason:"environment-allowed"}:{enabled:!1,environment,reason:"environment-excluded"}}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/env",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.74.69",
5
+ "version": "0.74.70",
6
6
  "description": "Stacks env helper methods.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -56,10 +56,10 @@
56
56
  "prepublishOnly": "bun run build"
57
57
  },
58
58
  "dependencies": {
59
- "@stacksjs/path": "0.74.69"
59
+ "@stacksjs/path": "0.74.70"
60
60
  },
61
61
  "devDependencies": {
62
62
  "better-dx": "^0.2.24",
63
- "@stacksjs/validation": "0.74.69"
63
+ "@stacksjs/validation": "0.74.70"
64
64
  }
65
65
  }