@productcraft/core 0.2.1 → 0.3.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 CHANGED
@@ -12,7 +12,8 @@ You **don't install this directly**. It's a runtime dependency of every product
12
12
  | { type: "bearer"; token: string } // pre-resolved JWT
13
13
  | { type: "cookie"; value: string } // captured auth_token
14
14
  ```
15
- - `PCClientConfig` — `{ auth?, baseUrl?, fetch? }`, the input shape every surface constructor takes.
15
+ - `PCClientConfig` — `{ auth?, baseUrl?, fetch? }`, the input shape every surface constructor takes. When `auth` is omitted, `resolveAuth` falls back to `PRODUCTCRAFT_API_KEY` from the environment (server-side only; never read without a `process` global).
16
+ - `PC_API_KEY_ENV` / `PC_AUTH_APP_ENV` / `readEnv` / `resolveAuth` — the env-fallback helpers. Hosts are never read from the environment.
16
17
  - `PC_BASE_URL` — the per-surface prod base URLs, used as defaults.
17
18
  - `makeClient<paths>(baseUrl, config)` — internal helper that wires an `openapi-fetch` client with the auth-header middleware.
18
19
 
package/dist/index.cjs CHANGED
@@ -18,6 +18,21 @@ var PC_BASE_URL = {
18
18
  social: "https://social.productcraft.co",
19
19
  trawl: "https://api.trawl.productcraft.co"
20
20
  };
21
+ var PC_API_KEY_ENV = "PRODUCTCRAFT_API_KEY";
22
+ var PC_AUTH_APP_ENV = "PRODUCTCRAFT_AUTH_APP";
23
+ function readEnv(name) {
24
+ const proc = globalThis.process;
25
+ if (typeof proc === "undefined" || !proc || !proc.env) return void 0;
26
+ const value = proc.env[name];
27
+ if (typeof value !== "string") return void 0;
28
+ const trimmed = value.trim();
29
+ return trimmed === "" ? void 0 : trimmed;
30
+ }
31
+ function resolveAuth(auth) {
32
+ if (auth) return auth;
33
+ const key = readEnv(PC_API_KEY_ENV);
34
+ return key ? { type: "apiKey", key } : void 0;
35
+ }
21
36
  function authMiddleware(auth) {
22
37
  return {
23
38
  async onRequest({ request }) {
@@ -42,12 +57,16 @@ function makeClient(defaultBaseUrl, config = {}) {
42
57
  baseUrl: config.baseUrl ?? defaultBaseUrl,
43
58
  fetch: config.fetch
44
59
  });
45
- client.use(authMiddleware(config.auth));
60
+ client.use(authMiddleware(resolveAuth(config.auth)));
46
61
  return client;
47
62
  }
48
63
 
64
+ exports.PC_API_KEY_ENV = PC_API_KEY_ENV;
65
+ exports.PC_AUTH_APP_ENV = PC_AUTH_APP_ENV;
49
66
  exports.PC_BASE_URL = PC_BASE_URL;
50
67
  exports.authMiddleware = authMiddleware;
51
68
  exports.makeClient = makeClient;
69
+ exports.readEnv = readEnv;
70
+ exports.resolveAuth = resolveAuth;
52
71
  //# sourceMappingURL=index.cjs.map
53
72
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["createClient"],"mappings":";;;;;;;;;AAgDO,IAAM,WAAA,GAAc;AAAA;AAAA;AAAA;AAAA,EAIzB,YAAA,EAAc,2CAAA;AAAA,EACd,IAAA,EAAM,kCAAA;AAAA,EACN,IAAA,EAAM,kCAAA;AAAA,EACN,QAAA,EAAU,sCAAA;AAAA,EACV,MAAA,EAAQ,gCAAA;AAAA,EACR,KAAA,EAAO;AACT;AAMO,SAAS,eAAe,IAAA,EAAsC;AACnE,EAAA,OAAO;AAAA,IACL,MAAM,SAAA,CAAU,EAAE,OAAA,EAAQ,EAAG;AAC3B,MAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,MAAA,QAAQ,KAAK,IAAA;AAAM,QACjB,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,GAAG,CAAA,CAAE,CAAA;AACzD,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAC3D,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,QAAA,EAAU,CAAA,WAAA,EAAc,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AACxD,UAAA;AAAA;AAEJ,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AACF;AAQO,SAAS,UAAA,CACd,cAAA,EACA,MAAA,GAAyB,EAAC,EACV;AAChB,EAAA,MAAM,SAASA,6BAAA,CAAqB;AAAA,IAClC,OAAA,EAAS,OAAO,OAAA,IAAW,cAAA;AAAA,IAC3B,OAAO,MAAA,CAAO;AAAA,GACf,CAAA;AACD,EAAA,MAAA,CAAO,GAAA,CAAI,cAAA,CAAe,MAAA,CAAO,IAAI,CAAC,CAAA;AACtC,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Shared transport + auth plumbing used by every surface client.\n *\n * Each surface package (`@productcraft/auth`, `@productcraft/mail`,\n * ...) defines a thin class around `openapi-fetch` plus the generated\n * `paths` types from its own `_generated.d.ts`. The class delegates\n * wire I/O to `openapi-fetch`, but exposes a Stripe-style ergonomic\n * surface where callers reach for `pc.mail.messages.send(...)` rather\n * than the underlying `client.POST(\"/v1/...\")` shape.\n *\n * v0 ships only the underlying `client` (named `client` on each\n * surface) — every endpoint is reachable through it. Ergonomic\n * resource surfaces land in v0.1+ as we hand-roll them.\n */\n\nimport createClient, { type Client, type Middleware } from \"openapi-fetch\";\n\n/**\n * The auth credential the SDK presents to ProductCraft APIs.\n *\n * - `apiKey` — Platform API Key (`pcft_live_*`). Server-side only;\n * never embed in a shipped browser bundle.\n * - `bearer` — pre-resolved JWT (e.g. an Auth app-scoped EndUser\n * token your backend minted and shipped to the device).\n * - `cookie` — captured `auth_token` cookie value. Mostly useful in\n * dev / E2E tests where you've already signed in.\n */\nexport type PCAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"bearer\"; token: string }\n | { type: \"cookie\"; value: string };\n\nexport interface PCClientConfig {\n auth?: PCAuth;\n /** Override the prod base URL — useful for dev / staging. */\n baseUrl?: string;\n /** Custom fetch (e.g. node-fetch with retries, undici, ...). */\n fetch?: typeof fetch;\n}\n\n/**\n * Default prod base URL per surface.\n *\n * Keys use the rebranded product names (Auth, Mail, Waitlist, Social)\n * matching the package + class names since the 2026-07 SDK rename.\n * Prior releases (`@productcraft/heimdall` 0.x etc.) exposed the same\n * hosts under the old keys (heimdall/envoi/rally/agora).\n */\nexport const PC_BASE_URL = {\n // platformAuth is the platform identity layer (workspaces, PATs);\n // it vacated api.auth so the customer-facing Auth product could\n // take that host.\n platformAuth: \"https://api.platform-auth.productcraft.co\",\n auth: \"https://api.auth.productcraft.co\",\n mail: \"https://api.mail.productcraft.co\",\n waitlist: \"https://api.waitlist.productcraft.co\",\n social: \"https://social.productcraft.co\",\n trawl: \"https://api.trawl.productcraft.co\",\n} as const;\n\n/**\n * Build an `openapi-fetch` middleware that adds the configured auth\n * credential as a header on every outbound request.\n */\nexport function authMiddleware(auth: PCAuth | undefined): Middleware {\n return {\n async onRequest({ request }) {\n if (!auth) return undefined;\n switch (auth.type) {\n case \"apiKey\":\n request.headers.set(\"Authorization\", `Bearer ${auth.key}`);\n break;\n case \"bearer\":\n request.headers.set(\"Authorization\", `Bearer ${auth.token}`);\n break;\n case \"cookie\":\n request.headers.set(\"Cookie\", `auth_token=${auth.value}`);\n break;\n }\n return request;\n },\n };\n}\n\n/**\n * Construct an `openapi-fetch` client for a surface. Each surface\n * package calls this with its own generated `paths` type and default\n * base URL. The returned client is the v0 surface — every endpoint is\n * reachable through `client.GET(...)`, `client.POST(...)`, etc.\n */\nexport function makeClient<TPaths extends object>(\n defaultBaseUrl: string,\n config: PCClientConfig = {},\n): Client<TPaths> {\n const client = createClient<TPaths>({\n baseUrl: config.baseUrl ?? defaultBaseUrl,\n fetch: config.fetch,\n });\n client.use(authMiddleware(config.auth));\n return client;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["createClient"],"mappings":";;;;;;;;;AAqDO,IAAM,WAAA,GAAc;AAAA;AAAA;AAAA;AAAA,EAIzB,YAAA,EAAc,2CAAA;AAAA,EACd,IAAA,EAAM,kCAAA;AAAA,EACN,IAAA,EAAM,kCAAA;AAAA,EACN,QAAA,EAAU,sCAAA;AAAA,EACV,MAAA,EAAQ,gCAAA;AAAA,EACR,KAAA,EAAO;AACT;AAGO,IAAM,cAAA,GAAiB;AAEvB,IAAM,eAAA,GAAkB;AAQxB,SAAS,QAAQ,IAAA,EAAkC;AACxD,EAAA,MAAM,OAAQ,UAAA,CACX,OAAA;AACH,EAAA,IAAI,OAAO,SAAS,WAAA,IAAe,CAAC,QAAQ,CAAC,IAAA,CAAK,KAAK,OAAO,MAAA;AAC9D,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA;AAC3B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,MAAA;AACtC,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,OAAO,OAAA,KAAY,KAAK,MAAA,GAAY,OAAA;AACtC;AAQO,SAAS,YAAY,IAAA,EAA8C;AACxE,EAAA,IAAI,MAAM,OAAO,IAAA;AACjB,EAAA,MAAM,GAAA,GAAM,QAAQ,cAAc,CAAA;AAClC,EAAA,OAAO,GAAA,GAAM,EAAE,IAAA,EAAM,QAAA,EAAU,KAAI,GAAI,MAAA;AACzC;AAMO,SAAS,eAAe,IAAA,EAAsC;AACnE,EAAA,OAAO;AAAA,IACL,MAAM,SAAA,CAAU,EAAE,OAAA,EAAQ,EAAG;AAC3B,MAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,MAAA,QAAQ,KAAK,IAAA;AAAM,QACjB,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,GAAG,CAAA,CAAE,CAAA;AACzD,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAC3D,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,QAAA,EAAU,CAAA,WAAA,EAAc,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AACxD,UAAA;AAAA;AAEJ,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AACF;AAWO,SAAS,UAAA,CACd,cAAA,EACA,MAAA,GAAyB,EAAC,EACV;AAChB,EAAA,MAAM,SAASA,6BAAA,CAAqB;AAAA,IAClC,OAAA,EAAS,OAAO,OAAA,IAAW,cAAA;AAAA,IAC3B,OAAO,MAAA,CAAO;AAAA,GACf,CAAA;AACD,EAAA,MAAA,CAAO,IAAI,cAAA,CAAe,WAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAC,CAAA;AACnD,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Shared transport + auth plumbing used by every surface client.\n *\n * Each surface package (`@productcraft/auth`, `@productcraft/mail`,\n * ...) defines a thin class around `openapi-fetch` plus the generated\n * `paths` types from its own `_generated.d.ts`. The class delegates\n * wire I/O to `openapi-fetch`, but exposes a Stripe-style ergonomic\n * surface where callers reach for `pc.mail.messages.send(...)` rather\n * than the underlying `client.POST(\"/v1/...\")` shape.\n *\n * v0 ships only the underlying `client` (named `client` on each\n * surface) — every endpoint is reachable through it. Ergonomic\n * resource surfaces land in v0.1+ as we hand-roll them.\n */\n\nimport createClient, { type Client, type Middleware } from \"openapi-fetch\";\n\n/**\n * The auth credential the SDK presents to ProductCraft APIs.\n *\n * - `apiKey` — Platform API Key (`pcft_live_*`). Server-side only;\n * never embed in a shipped browser bundle.\n * - `bearer` — pre-resolved JWT (e.g. an Auth app-scoped EndUser\n * token your backend minted and shipped to the device).\n * - `cookie` — captured `auth_token` cookie value. Mostly useful in\n * dev / E2E tests where you've already signed in.\n */\nexport type PCAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"bearer\"; token: string }\n | { type: \"cookie\"; value: string };\n\nexport interface PCClientConfig {\n /**\n * Credential for every request. Server-side, omit it to fall back to\n * the `PRODUCTCRAFT_API_KEY` environment variable (your `pcft_`\n * workspace key). An explicit value always wins over the environment.\n */\n auth?: PCAuth;\n /** Override the prod base URL — useful for dev / staging. */\n baseUrl?: string;\n /** Custom fetch (e.g. node-fetch with retries, undici, ...). */\n fetch?: typeof fetch;\n}\n\n/**\n * Default prod base URL per surface.\n *\n * Keys use the rebranded product names (Auth, Mail, Waitlist, Social)\n * matching the package + class names since the 2026-07 SDK rename.\n * Prior releases (`@productcraft/heimdall` 0.x etc.) exposed the same\n * hosts under the old keys (heimdall/envoi/rally/agora).\n */\nexport const PC_BASE_URL = {\n // platformAuth is the platform identity layer (workspaces, PATs);\n // it vacated api.auth so the customer-facing Auth product could\n // take that host.\n platformAuth: \"https://api.platform-auth.productcraft.co\",\n auth: \"https://api.auth.productcraft.co\",\n mail: \"https://api.mail.productcraft.co\",\n waitlist: \"https://api.waitlist.productcraft.co\",\n social: \"https://social.productcraft.co\",\n trawl: \"https://api.trawl.productcraft.co\",\n} as const;\n\n/** Environment variable holding the `pcft_` workspace API key. */\nexport const PC_API_KEY_ENV = \"PRODUCTCRAFT_API_KEY\";\n/** Environment variable holding the default Auth app slug for `auth.consumer()`. */\nexport const PC_AUTH_APP_ENV = \"PRODUCTCRAFT_AUTH_APP\";\n\n/**\n * Read an environment variable when running somewhere with a `process`\n * global (Node, Bun, Deno's Node compat). Returns `undefined` in the\n * browser or edge runtimes without `process`, and for empty values.\n * Never throws.\n */\nexport function readEnv(name: string): string | undefined {\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } })\n .process;\n if (typeof proc === \"undefined\" || !proc || !proc.env) return undefined;\n const value = proc.env[name];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Resolve the credential a server-side client should present: the\n * explicit `auth` when given, otherwise `PRODUCTCRAFT_API_KEY` from the\n * environment, otherwise none. Hosts are never read from the\n * environment; override them in code with `baseUrl`.\n */\nexport function resolveAuth(auth: PCAuth | undefined): PCAuth | undefined {\n if (auth) return auth;\n const key = readEnv(PC_API_KEY_ENV);\n return key ? { type: \"apiKey\", key } : undefined;\n}\n\n/**\n * Build an `openapi-fetch` middleware that adds the configured auth\n * credential as a header on every outbound request.\n */\nexport function authMiddleware(auth: PCAuth | undefined): Middleware {\n return {\n async onRequest({ request }) {\n if (!auth) return undefined;\n switch (auth.type) {\n case \"apiKey\":\n request.headers.set(\"Authorization\", `Bearer ${auth.key}`);\n break;\n case \"bearer\":\n request.headers.set(\"Authorization\", `Bearer ${auth.token}`);\n break;\n case \"cookie\":\n request.headers.set(\"Cookie\", `auth_token=${auth.value}`);\n break;\n }\n return request;\n },\n };\n}\n\n/**\n * Construct an `openapi-fetch` client for a surface. Each surface\n * package calls this with its own generated `paths` type and default\n * base URL. The returned client is the v0 surface — every endpoint is\n * reachable through `client.GET(...)`, `client.POST(...)`, etc.\n *\n * When `config.auth` is omitted the client falls back to\n * `PRODUCTCRAFT_API_KEY` (see `resolveAuth`).\n */\nexport function makeClient<TPaths extends object>(\n defaultBaseUrl: string,\n config: PCClientConfig = {},\n): Client<TPaths> {\n const client = createClient<TPaths>({\n baseUrl: config.baseUrl ?? defaultBaseUrl,\n fetch: config.fetch,\n });\n client.use(authMiddleware(resolveAuth(config.auth)));\n return client;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -36,6 +36,11 @@ type PCAuth = {
36
36
  value: string;
37
37
  };
38
38
  interface PCClientConfig {
39
+ /**
40
+ * Credential for every request. Server-side, omit it to fall back to
41
+ * the `PRODUCTCRAFT_API_KEY` environment variable (your `pcft_`
42
+ * workspace key). An explicit value always wins over the environment.
43
+ */
39
44
  auth?: PCAuth;
40
45
  /** Override the prod base URL — useful for dev / staging. */
41
46
  baseUrl?: string;
@@ -58,6 +63,24 @@ declare const PC_BASE_URL: {
58
63
  readonly social: "https://social.productcraft.co";
59
64
  readonly trawl: "https://api.trawl.productcraft.co";
60
65
  };
66
+ /** Environment variable holding the `pcft_` workspace API key. */
67
+ declare const PC_API_KEY_ENV = "PRODUCTCRAFT_API_KEY";
68
+ /** Environment variable holding the default Auth app slug for `auth.consumer()`. */
69
+ declare const PC_AUTH_APP_ENV = "PRODUCTCRAFT_AUTH_APP";
70
+ /**
71
+ * Read an environment variable when running somewhere with a `process`
72
+ * global (Node, Bun, Deno's Node compat). Returns `undefined` in the
73
+ * browser or edge runtimes without `process`, and for empty values.
74
+ * Never throws.
75
+ */
76
+ declare function readEnv(name: string): string | undefined;
77
+ /**
78
+ * Resolve the credential a server-side client should present: the
79
+ * explicit `auth` when given, otherwise `PRODUCTCRAFT_API_KEY` from the
80
+ * environment, otherwise none. Hosts are never read from the
81
+ * environment; override them in code with `baseUrl`.
82
+ */
83
+ declare function resolveAuth(auth: PCAuth | undefined): PCAuth | undefined;
61
84
  /**
62
85
  * Build an `openapi-fetch` middleware that adds the configured auth
63
86
  * credential as a header on every outbound request.
@@ -68,7 +91,10 @@ declare function authMiddleware(auth: PCAuth | undefined): Middleware;
68
91
  * package calls this with its own generated `paths` type and default
69
92
  * base URL. The returned client is the v0 surface — every endpoint is
70
93
  * reachable through `client.GET(...)`, `client.POST(...)`, etc.
94
+ *
95
+ * When `config.auth` is omitted the client falls back to
96
+ * `PRODUCTCRAFT_API_KEY` (see `resolveAuth`).
71
97
  */
72
98
  declare function makeClient<TPaths extends object>(defaultBaseUrl: string, config?: PCClientConfig): Client<TPaths>;
73
99
 
74
- export { type PCAuth, type PCClientConfig, PC_BASE_URL, authMiddleware, makeClient };
100
+ export { type PCAuth, type PCClientConfig, PC_API_KEY_ENV, PC_AUTH_APP_ENV, PC_BASE_URL, authMiddleware, makeClient, readEnv, resolveAuth };
package/dist/index.d.ts CHANGED
@@ -36,6 +36,11 @@ type PCAuth = {
36
36
  value: string;
37
37
  };
38
38
  interface PCClientConfig {
39
+ /**
40
+ * Credential for every request. Server-side, omit it to fall back to
41
+ * the `PRODUCTCRAFT_API_KEY` environment variable (your `pcft_`
42
+ * workspace key). An explicit value always wins over the environment.
43
+ */
39
44
  auth?: PCAuth;
40
45
  /** Override the prod base URL — useful for dev / staging. */
41
46
  baseUrl?: string;
@@ -58,6 +63,24 @@ declare const PC_BASE_URL: {
58
63
  readonly social: "https://social.productcraft.co";
59
64
  readonly trawl: "https://api.trawl.productcraft.co";
60
65
  };
66
+ /** Environment variable holding the `pcft_` workspace API key. */
67
+ declare const PC_API_KEY_ENV = "PRODUCTCRAFT_API_KEY";
68
+ /** Environment variable holding the default Auth app slug for `auth.consumer()`. */
69
+ declare const PC_AUTH_APP_ENV = "PRODUCTCRAFT_AUTH_APP";
70
+ /**
71
+ * Read an environment variable when running somewhere with a `process`
72
+ * global (Node, Bun, Deno's Node compat). Returns `undefined` in the
73
+ * browser or edge runtimes without `process`, and for empty values.
74
+ * Never throws.
75
+ */
76
+ declare function readEnv(name: string): string | undefined;
77
+ /**
78
+ * Resolve the credential a server-side client should present: the
79
+ * explicit `auth` when given, otherwise `PRODUCTCRAFT_API_KEY` from the
80
+ * environment, otherwise none. Hosts are never read from the
81
+ * environment; override them in code with `baseUrl`.
82
+ */
83
+ declare function resolveAuth(auth: PCAuth | undefined): PCAuth | undefined;
61
84
  /**
62
85
  * Build an `openapi-fetch` middleware that adds the configured auth
63
86
  * credential as a header on every outbound request.
@@ -68,7 +91,10 @@ declare function authMiddleware(auth: PCAuth | undefined): Middleware;
68
91
  * package calls this with its own generated `paths` type and default
69
92
  * base URL. The returned client is the v0 surface — every endpoint is
70
93
  * reachable through `client.GET(...)`, `client.POST(...)`, etc.
94
+ *
95
+ * When `config.auth` is omitted the client falls back to
96
+ * `PRODUCTCRAFT_API_KEY` (see `resolveAuth`).
71
97
  */
72
98
  declare function makeClient<TPaths extends object>(defaultBaseUrl: string, config?: PCClientConfig): Client<TPaths>;
73
99
 
74
- export { type PCAuth, type PCClientConfig, PC_BASE_URL, authMiddleware, makeClient };
100
+ export { type PCAuth, type PCClientConfig, PC_API_KEY_ENV, PC_AUTH_APP_ENV, PC_BASE_URL, authMiddleware, makeClient, readEnv, resolveAuth };
package/dist/index.js CHANGED
@@ -12,6 +12,21 @@ var PC_BASE_URL = {
12
12
  social: "https://social.productcraft.co",
13
13
  trawl: "https://api.trawl.productcraft.co"
14
14
  };
15
+ var PC_API_KEY_ENV = "PRODUCTCRAFT_API_KEY";
16
+ var PC_AUTH_APP_ENV = "PRODUCTCRAFT_AUTH_APP";
17
+ function readEnv(name) {
18
+ const proc = globalThis.process;
19
+ if (typeof proc === "undefined" || !proc || !proc.env) return void 0;
20
+ const value = proc.env[name];
21
+ if (typeof value !== "string") return void 0;
22
+ const trimmed = value.trim();
23
+ return trimmed === "" ? void 0 : trimmed;
24
+ }
25
+ function resolveAuth(auth) {
26
+ if (auth) return auth;
27
+ const key = readEnv(PC_API_KEY_ENV);
28
+ return key ? { type: "apiKey", key } : void 0;
29
+ }
15
30
  function authMiddleware(auth) {
16
31
  return {
17
32
  async onRequest({ request }) {
@@ -36,10 +51,10 @@ function makeClient(defaultBaseUrl, config = {}) {
36
51
  baseUrl: config.baseUrl ?? defaultBaseUrl,
37
52
  fetch: config.fetch
38
53
  });
39
- client.use(authMiddleware(config.auth));
54
+ client.use(authMiddleware(resolveAuth(config.auth)));
40
55
  return client;
41
56
  }
42
57
 
43
- export { PC_BASE_URL, authMiddleware, makeClient };
58
+ export { PC_API_KEY_ENV, PC_AUTH_APP_ENV, PC_BASE_URL, authMiddleware, makeClient, readEnv, resolveAuth };
44
59
  //# sourceMappingURL=index.js.map
45
60
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAgDO,IAAM,WAAA,GAAc;AAAA;AAAA;AAAA;AAAA,EAIzB,YAAA,EAAc,2CAAA;AAAA,EACd,IAAA,EAAM,kCAAA;AAAA,EACN,IAAA,EAAM,kCAAA;AAAA,EACN,QAAA,EAAU,sCAAA;AAAA,EACV,MAAA,EAAQ,gCAAA;AAAA,EACR,KAAA,EAAO;AACT;AAMO,SAAS,eAAe,IAAA,EAAsC;AACnE,EAAA,OAAO;AAAA,IACL,MAAM,SAAA,CAAU,EAAE,OAAA,EAAQ,EAAG;AAC3B,MAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,MAAA,QAAQ,KAAK,IAAA;AAAM,QACjB,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,GAAG,CAAA,CAAE,CAAA;AACzD,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAC3D,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,QAAA,EAAU,CAAA,WAAA,EAAc,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AACxD,UAAA;AAAA;AAEJ,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AACF;AAQO,SAAS,UAAA,CACd,cAAA,EACA,MAAA,GAAyB,EAAC,EACV;AAChB,EAAA,MAAM,SAAS,YAAA,CAAqB;AAAA,IAClC,OAAA,EAAS,OAAO,OAAA,IAAW,cAAA;AAAA,IAC3B,OAAO,MAAA,CAAO;AAAA,GACf,CAAA;AACD,EAAA,MAAA,CAAO,GAAA,CAAI,cAAA,CAAe,MAAA,CAAO,IAAI,CAAC,CAAA;AACtC,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["/**\n * Shared transport + auth plumbing used by every surface client.\n *\n * Each surface package (`@productcraft/auth`, `@productcraft/mail`,\n * ...) defines a thin class around `openapi-fetch` plus the generated\n * `paths` types from its own `_generated.d.ts`. The class delegates\n * wire I/O to `openapi-fetch`, but exposes a Stripe-style ergonomic\n * surface where callers reach for `pc.mail.messages.send(...)` rather\n * than the underlying `client.POST(\"/v1/...\")` shape.\n *\n * v0 ships only the underlying `client` (named `client` on each\n * surface) — every endpoint is reachable through it. Ergonomic\n * resource surfaces land in v0.1+ as we hand-roll them.\n */\n\nimport createClient, { type Client, type Middleware } from \"openapi-fetch\";\n\n/**\n * The auth credential the SDK presents to ProductCraft APIs.\n *\n * - `apiKey` — Platform API Key (`pcft_live_*`). Server-side only;\n * never embed in a shipped browser bundle.\n * - `bearer` — pre-resolved JWT (e.g. an Auth app-scoped EndUser\n * token your backend minted and shipped to the device).\n * - `cookie` — captured `auth_token` cookie value. Mostly useful in\n * dev / E2E tests where you've already signed in.\n */\nexport type PCAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"bearer\"; token: string }\n | { type: \"cookie\"; value: string };\n\nexport interface PCClientConfig {\n auth?: PCAuth;\n /** Override the prod base URL — useful for dev / staging. */\n baseUrl?: string;\n /** Custom fetch (e.g. node-fetch with retries, undici, ...). */\n fetch?: typeof fetch;\n}\n\n/**\n * Default prod base URL per surface.\n *\n * Keys use the rebranded product names (Auth, Mail, Waitlist, Social)\n * matching the package + class names since the 2026-07 SDK rename.\n * Prior releases (`@productcraft/heimdall` 0.x etc.) exposed the same\n * hosts under the old keys (heimdall/envoi/rally/agora).\n */\nexport const PC_BASE_URL = {\n // platformAuth is the platform identity layer (workspaces, PATs);\n // it vacated api.auth so the customer-facing Auth product could\n // take that host.\n platformAuth: \"https://api.platform-auth.productcraft.co\",\n auth: \"https://api.auth.productcraft.co\",\n mail: \"https://api.mail.productcraft.co\",\n waitlist: \"https://api.waitlist.productcraft.co\",\n social: \"https://social.productcraft.co\",\n trawl: \"https://api.trawl.productcraft.co\",\n} as const;\n\n/**\n * Build an `openapi-fetch` middleware that adds the configured auth\n * credential as a header on every outbound request.\n */\nexport function authMiddleware(auth: PCAuth | undefined): Middleware {\n return {\n async onRequest({ request }) {\n if (!auth) return undefined;\n switch (auth.type) {\n case \"apiKey\":\n request.headers.set(\"Authorization\", `Bearer ${auth.key}`);\n break;\n case \"bearer\":\n request.headers.set(\"Authorization\", `Bearer ${auth.token}`);\n break;\n case \"cookie\":\n request.headers.set(\"Cookie\", `auth_token=${auth.value}`);\n break;\n }\n return request;\n },\n };\n}\n\n/**\n * Construct an `openapi-fetch` client for a surface. Each surface\n * package calls this with its own generated `paths` type and default\n * base URL. The returned client is the v0 surface — every endpoint is\n * reachable through `client.GET(...)`, `client.POST(...)`, etc.\n */\nexport function makeClient<TPaths extends object>(\n defaultBaseUrl: string,\n config: PCClientConfig = {},\n): Client<TPaths> {\n const client = createClient<TPaths>({\n baseUrl: config.baseUrl ?? defaultBaseUrl,\n fetch: config.fetch,\n });\n client.use(authMiddleware(config.auth));\n return client;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAqDO,IAAM,WAAA,GAAc;AAAA;AAAA;AAAA;AAAA,EAIzB,YAAA,EAAc,2CAAA;AAAA,EACd,IAAA,EAAM,kCAAA;AAAA,EACN,IAAA,EAAM,kCAAA;AAAA,EACN,QAAA,EAAU,sCAAA;AAAA,EACV,MAAA,EAAQ,gCAAA;AAAA,EACR,KAAA,EAAO;AACT;AAGO,IAAM,cAAA,GAAiB;AAEvB,IAAM,eAAA,GAAkB;AAQxB,SAAS,QAAQ,IAAA,EAAkC;AACxD,EAAA,MAAM,OAAQ,UAAA,CACX,OAAA;AACH,EAAA,IAAI,OAAO,SAAS,WAAA,IAAe,CAAC,QAAQ,CAAC,IAAA,CAAK,KAAK,OAAO,MAAA;AAC9D,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA;AAC3B,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,MAAA;AACtC,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,OAAO,OAAA,KAAY,KAAK,MAAA,GAAY,OAAA;AACtC;AAQO,SAAS,YAAY,IAAA,EAA8C;AACxE,EAAA,IAAI,MAAM,OAAO,IAAA;AACjB,EAAA,MAAM,GAAA,GAAM,QAAQ,cAAc,CAAA;AAClC,EAAA,OAAO,GAAA,GAAM,EAAE,IAAA,EAAM,QAAA,EAAU,KAAI,GAAI,MAAA;AACzC;AAMO,SAAS,eAAe,IAAA,EAAsC;AACnE,EAAA,OAAO;AAAA,IACL,MAAM,SAAA,CAAU,EAAE,OAAA,EAAQ,EAAG;AAC3B,MAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,MAAA,QAAQ,KAAK,IAAA;AAAM,QACjB,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,GAAG,CAAA,CAAE,CAAA;AACzD,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AAC3D,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,OAAA,CAAQ,QAAQ,GAAA,CAAI,QAAA,EAAU,CAAA,WAAA,EAAc,IAAA,CAAK,KAAK,CAAA,CAAE,CAAA;AACxD,UAAA;AAAA;AAEJ,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AACF;AAWO,SAAS,UAAA,CACd,cAAA,EACA,MAAA,GAAyB,EAAC,EACV;AAChB,EAAA,MAAM,SAAS,YAAA,CAAqB;AAAA,IAClC,OAAA,EAAS,OAAO,OAAA,IAAW,cAAA;AAAA,IAC3B,OAAO,MAAA,CAAO;AAAA,GACf,CAAA;AACD,EAAA,MAAA,CAAO,IAAI,cAAA,CAAe,WAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAC,CAAA;AACnD,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["/**\n * Shared transport + auth plumbing used by every surface client.\n *\n * Each surface package (`@productcraft/auth`, `@productcraft/mail`,\n * ...) defines a thin class around `openapi-fetch` plus the generated\n * `paths` types from its own `_generated.d.ts`. The class delegates\n * wire I/O to `openapi-fetch`, but exposes a Stripe-style ergonomic\n * surface where callers reach for `pc.mail.messages.send(...)` rather\n * than the underlying `client.POST(\"/v1/...\")` shape.\n *\n * v0 ships only the underlying `client` (named `client` on each\n * surface) — every endpoint is reachable through it. Ergonomic\n * resource surfaces land in v0.1+ as we hand-roll them.\n */\n\nimport createClient, { type Client, type Middleware } from \"openapi-fetch\";\n\n/**\n * The auth credential the SDK presents to ProductCraft APIs.\n *\n * - `apiKey` — Platform API Key (`pcft_live_*`). Server-side only;\n * never embed in a shipped browser bundle.\n * - `bearer` — pre-resolved JWT (e.g. an Auth app-scoped EndUser\n * token your backend minted and shipped to the device).\n * - `cookie` — captured `auth_token` cookie value. Mostly useful in\n * dev / E2E tests where you've already signed in.\n */\nexport type PCAuth =\n | { type: \"apiKey\"; key: string }\n | { type: \"bearer\"; token: string }\n | { type: \"cookie\"; value: string };\n\nexport interface PCClientConfig {\n /**\n * Credential for every request. Server-side, omit it to fall back to\n * the `PRODUCTCRAFT_API_KEY` environment variable (your `pcft_`\n * workspace key). An explicit value always wins over the environment.\n */\n auth?: PCAuth;\n /** Override the prod base URL — useful for dev / staging. */\n baseUrl?: string;\n /** Custom fetch (e.g. node-fetch with retries, undici, ...). */\n fetch?: typeof fetch;\n}\n\n/**\n * Default prod base URL per surface.\n *\n * Keys use the rebranded product names (Auth, Mail, Waitlist, Social)\n * matching the package + class names since the 2026-07 SDK rename.\n * Prior releases (`@productcraft/heimdall` 0.x etc.) exposed the same\n * hosts under the old keys (heimdall/envoi/rally/agora).\n */\nexport const PC_BASE_URL = {\n // platformAuth is the platform identity layer (workspaces, PATs);\n // it vacated api.auth so the customer-facing Auth product could\n // take that host.\n platformAuth: \"https://api.platform-auth.productcraft.co\",\n auth: \"https://api.auth.productcraft.co\",\n mail: \"https://api.mail.productcraft.co\",\n waitlist: \"https://api.waitlist.productcraft.co\",\n social: \"https://social.productcraft.co\",\n trawl: \"https://api.trawl.productcraft.co\",\n} as const;\n\n/** Environment variable holding the `pcft_` workspace API key. */\nexport const PC_API_KEY_ENV = \"PRODUCTCRAFT_API_KEY\";\n/** Environment variable holding the default Auth app slug for `auth.consumer()`. */\nexport const PC_AUTH_APP_ENV = \"PRODUCTCRAFT_AUTH_APP\";\n\n/**\n * Read an environment variable when running somewhere with a `process`\n * global (Node, Bun, Deno's Node compat). Returns `undefined` in the\n * browser or edge runtimes without `process`, and for empty values.\n * Never throws.\n */\nexport function readEnv(name: string): string | undefined {\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } })\n .process;\n if (typeof proc === \"undefined\" || !proc || !proc.env) return undefined;\n const value = proc.env[name];\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed === \"\" ? undefined : trimmed;\n}\n\n/**\n * Resolve the credential a server-side client should present: the\n * explicit `auth` when given, otherwise `PRODUCTCRAFT_API_KEY` from the\n * environment, otherwise none. Hosts are never read from the\n * environment; override them in code with `baseUrl`.\n */\nexport function resolveAuth(auth: PCAuth | undefined): PCAuth | undefined {\n if (auth) return auth;\n const key = readEnv(PC_API_KEY_ENV);\n return key ? { type: \"apiKey\", key } : undefined;\n}\n\n/**\n * Build an `openapi-fetch` middleware that adds the configured auth\n * credential as a header on every outbound request.\n */\nexport function authMiddleware(auth: PCAuth | undefined): Middleware {\n return {\n async onRequest({ request }) {\n if (!auth) return undefined;\n switch (auth.type) {\n case \"apiKey\":\n request.headers.set(\"Authorization\", `Bearer ${auth.key}`);\n break;\n case \"bearer\":\n request.headers.set(\"Authorization\", `Bearer ${auth.token}`);\n break;\n case \"cookie\":\n request.headers.set(\"Cookie\", `auth_token=${auth.value}`);\n break;\n }\n return request;\n },\n };\n}\n\n/**\n * Construct an `openapi-fetch` client for a surface. Each surface\n * package calls this with its own generated `paths` type and default\n * base URL. The returned client is the v0 surface — every endpoint is\n * reachable through `client.GET(...)`, `client.POST(...)`, etc.\n *\n * When `config.auth` is omitted the client falls back to\n * `PRODUCTCRAFT_API_KEY` (see `resolveAuth`).\n */\nexport function makeClient<TPaths extends object>(\n defaultBaseUrl: string,\n config: PCClientConfig = {},\n): Client<TPaths> {\n const client = createClient<TPaths>({\n baseUrl: config.baseUrl ?? defaultBaseUrl,\n fetch: config.fetch,\n });\n client.use(authMiddleware(resolveAuth(config.auth)));\n return client;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productcraft/core",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Shared transport, auth, and config primitives for the ProductCraft SDKs. Depended on by every per-surface package.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",