@nebutra/provider-factory 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebutra/provider-factory",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Neutral provider-resolution primitive: the identical 'explicit ?? env ?? detect-chain ?? fallback' selection + prod-guard shared by every provider-agnostic Nebutra package. No instantiation logic.",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -10,10 +10,14 @@
10
10
  "category": "platform",
11
11
  "summary": "Shared provider-type resolution + prod safety guard"
12
12
  },
13
- "main": "./src/index.ts",
14
- "types": "./src/index.ts",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
15
  "exports": {
16
- ".": "./src/index.ts"
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "default": "./dist/index.js"
20
+ }
17
21
  },
18
22
  "dependencies": {},
19
23
  "devDependencies": {
@@ -34,6 +38,12 @@
34
38
  "publishConfig": {
35
39
  "access": "public"
36
40
  },
41
+ "files": [
42
+ "dist",
43
+ "README.md",
44
+ "LICENSE",
45
+ "CHANGELOG.md"
46
+ ],
37
47
  "scripts": {
38
48
  "build": "tsup",
39
49
  "test": "vitest run",
@@ -1,17 +0,0 @@
1
-
2
- > @nebutra/provider-factory@0.2.2 build /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/platform/provider-factory
3
- > tsup
4
-
5
- CLI Building entry: src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.1
8
- CLI Using tsup config: /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/platform/provider-factory/tsup.config.ts
9
- CLI Target: es2022
10
- CLI Cleaning output folder
11
- ESM Build start
12
- ESM dist/index.js 997.00 B
13
- ESM dist/index.js.map 3.97 KB
14
- ESM ⚡️ Build success in 19ms
15
- DTS Build start
16
- DTS ⚡️ Build success in 2777ms
17
- DTS dist/index.d.ts 2.53 KB
@@ -1,14 +0,0 @@
1
-
2
- > @nebutra/provider-factory@0.2.1 test /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/platform/provider-factory
3
- > vitest run
4
-
5
-
6
- RUN v4.1.4 /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/platform/provider-factory
7
-
8
- ✓ src/__tests__/provider-factory.test.ts (9 tests) 3ms
9
-
10
- Test Files 1 passed (1)
11
- Tests 9 passed (9)
12
- Start at 09:38:26
13
- Duration 204ms (transform 26ms, setup 0ms, import 37ms, tests 3ms, environment 0ms)
14
-
@@ -1,4 +0,0 @@
1
-
2
- > @nebutra/provider-factory@0.2.2 typecheck /Users/tseka_luk/Documents/Nebutra-SaaS-Lab/Nebutra-Sailor/packages/platform/provider-factory
3
- > tsc --noEmit
4
-
@@ -1,110 +0,0 @@
1
- import { afterEach, describe, expect, it } from "vitest";
2
- import { assertProviderAllowed, envPresent, resolveProviderType } from "../index";
3
-
4
- const SAVED = { ...process.env };
5
- afterEach(() => {
6
- process.env = { ...SAVED };
7
- });
8
-
9
- type P = "qstash" | "bullmq" | "memory";
10
-
11
- const detectors = [
12
- { provider: "qstash" as P, when: envPresent("QSTASH_TOKEN") },
13
- { provider: "bullmq" as P, when: envPresent("REDIS_URL") },
14
- ];
15
-
16
- describe("resolveProviderType precedence", () => {
17
- it("1. explicit config wins over everything", () => {
18
- process.env.QUEUE_PROVIDER = "bullmq";
19
- process.env.QSTASH_TOKEN = "x";
20
- expect(
21
- resolveProviderType<P>({
22
- explicit: "memory",
23
- envVarName: "QUEUE_PROVIDER",
24
- detectors,
25
- fallback: "memory",
26
- }),
27
- ).toBe("memory");
28
- });
29
-
30
- it("2. env var beats detection", () => {
31
- process.env.QSTASH_TOKEN = "x"; // would detect qstash
32
- process.env.QUEUE_PROVIDER = "bullmq";
33
- expect(
34
- resolveProviderType<P>({ envVarName: "QUEUE_PROVIDER", detectors, fallback: "memory" }),
35
- ).toBe("bullmq");
36
- });
37
-
38
- it("3. detection chain order is honoured", () => {
39
- process.env.QUEUE_PROVIDER = undefined;
40
- process.env.REDIS_URL = "redis://x";
41
- expect(
42
- resolveProviderType<P>({ envVarName: "QUEUE_PROVIDER", detectors, fallback: "memory" }),
43
- ).toBe("bullmq");
44
- process.env.QSTASH_TOKEN = "x";
45
- expect(
46
- resolveProviderType<P>({ envVarName: "QUEUE_PROVIDER", detectors, fallback: "memory" }),
47
- ).toBe("qstash"); // earlier detector wins
48
- });
49
-
50
- it("4. fallback when nothing matches", () => {
51
- expect(
52
- resolveProviderType<P>({ envVarName: "QUEUE_PROVIDER", detectors, fallback: "memory" }),
53
- ).toBe("memory");
54
- });
55
-
56
- it("trims/ignores an empty env var", () => {
57
- process.env.QUEUE_PROVIDER = " ";
58
- expect(
59
- resolveProviderType<P>({ envVarName: "QUEUE_PROVIDER", detectors, fallback: "memory" }),
60
- ).toBe("memory");
61
- });
62
- });
63
-
64
- describe("envPresent", () => {
65
- it("is true only for a non-empty value", () => {
66
- process.env.X = "";
67
- expect(envPresent("X")()).toBe(false);
68
- process.env.X = "v";
69
- expect(envPresent("X")()).toBe(true);
70
- });
71
- });
72
-
73
- describe("assertProviderAllowed", () => {
74
- it("throws for a disallowed provider in production unless overridden", () => {
75
- process.env.NODE_ENV = "production";
76
- expect(() =>
77
- assertProviderAllowed("memory", {
78
- disallowedInProd: ["memory"],
79
- overrideEnv: "ALLOW_MEMORY",
80
- hint: "configure REDIS_URL",
81
- }),
82
- ).toThrow(/production/);
83
- process.env.ALLOW_MEMORY = "true";
84
- expect(() =>
85
- assertProviderAllowed("memory", {
86
- disallowedInProd: ["memory"],
87
- overrideEnv: "ALLOW_MEMORY",
88
- hint: "configure REDIS_URL",
89
- }),
90
- ).not.toThrow();
91
- });
92
-
93
- it("throws the caller's exact message when provided", () => {
94
- process.env.NODE_ENV = "production";
95
- expect(() =>
96
- assertProviderAllowed("memory", {
97
- disallowedInProd: ["memory"],
98
- overrideEnv: "X",
99
- message: "Refusing to use the in-memory queue provider in production",
100
- }),
101
- ).toThrow("Refusing to use the in-memory queue provider in production");
102
- });
103
-
104
- it("never throws outside production", () => {
105
- process.env.NODE_ENV = "test";
106
- expect(() =>
107
- assertProviderAllowed("memory", { disallowedInProd: ["memory"], overrideEnv: "X" }),
108
- ).not.toThrow();
109
- });
110
- });
package/src/index.ts DELETED
@@ -1,86 +0,0 @@
1
- /**
2
- * @nebutra/provider-factory — the neutral provider-resolution primitive.
3
- *
4
- * Every provider-agnostic Nebutra package (queue, search, notifications,
5
- * vault, uploads, …) repeated the exact same selection:
6
- *
7
- * providerType = explicit ?? env[`${X}_PROVIDER`] ?? detect-chain ?? fallback
8
- *
9
- * plus a "refuse the in-memory provider in production" guard. That selection
10
- * is identical and domain-free; only the subsequent *instantiation* switch
11
- * (dynamic-importing the concrete provider) is domain-specific and stays in
12
- * each package. This module owns the selection, nothing else.
13
- */
14
-
15
- /** One auto-detection rule: pick `provider` when `when()` is true. */
16
- export interface ProviderDetector<T extends string> {
17
- readonly provider: T;
18
- readonly when: () => boolean;
19
- }
20
-
21
- /** `true` when the named env var is set to a non-empty (trimmed) value. */
22
- export function envPresent(name: string): () => boolean {
23
- return () => {
24
- const v = process.env[name];
25
- return typeof v === "string" && v.trim().length > 0;
26
- };
27
- }
28
-
29
- export interface ResolveProviderInput<T extends string> {
30
- /** Explicit caller config — highest precedence. */
31
- readonly explicit?: T | undefined;
32
- /** Env var holding an explicit provider name (e.g. `QUEUE_PROVIDER`). */
33
- readonly envVarName: string;
34
- /** Ordered auto-detection rules; first match wins. */
35
- readonly detectors: ReadonlyArray<ProviderDetector<T>>;
36
- /** Used when nothing else resolves. */
37
- readonly fallback: T;
38
- }
39
-
40
- /**
41
- * Resolve the provider type. Precedence: explicit → env var → detector chain
42
- * (in order) → fallback. An empty/whitespace env var is ignored.
43
- */
44
- export function resolveProviderType<T extends string>(input: ResolveProviderInput<T>): T {
45
- if (input.explicit) return input.explicit;
46
- const fromEnv = process.env[input.envVarName]?.trim();
47
- if (fromEnv) return fromEnv as T;
48
- for (const d of input.detectors) {
49
- if (d.when()) return d.provider;
50
- }
51
- return input.fallback;
52
- }
53
-
54
- export interface ProdGuardOptions<T extends string> {
55
- /** Providers that must not run in production. */
56
- readonly disallowedInProd: readonly T[];
57
- /** Env var that, when "true", permits the disallowed provider anyway. */
58
- readonly overrideEnv: string;
59
- /** Optional remediation hint appended to the default error. */
60
- readonly hint?: string;
61
- /**
62
- * Exact error message to throw, overriding the default. Use this to keep a
63
- * package's existing wording (error strings are domain copy, not shared
64
- * logic — only the prod-detection is shared).
65
- */
66
- readonly message?: string;
67
- }
68
-
69
- /**
70
- * Refuse a disallowed provider in production unless the override env is set.
71
- * No-op outside `NODE_ENV==="production"`.
72
- */
73
- export function assertProviderAllowed<T extends string>(
74
- provider: T,
75
- opts: ProdGuardOptions<T>,
76
- ): void {
77
- if (process.env.NODE_ENV !== "production") return;
78
- if (!opts.disallowedInProd.includes(provider)) return;
79
- if (process.env[opts.overrideEnv] === "true") return;
80
- if (opts.message) throw new Error(opts.message);
81
- throw new Error(
82
- `Refusing to use the "${provider}" provider in production. ` +
83
- `${opts.hint ? `${opts.hint}. ` : ""}` +
84
- `Set ${opts.overrideEnv}=true for an explicit temporary override.`,
85
- );
86
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src",
6
- "incremental": false
7
- },
8
- "include": ["src/**/*.ts"],
9
- "exclude": ["node_modules", "dist"]
10
- }
package/tsup.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- entry: ["src/index.ts"],
5
- format: ["esm"],
6
- dts: true,
7
- clean: true,
8
- sourcemap: true,
9
- target: "es2022",
10
- });