primitive-app 3.2.0-alpha.14 → 3.2.0-alpha.15

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.
@@ -9,8 +9,16 @@ export interface BlobItem {
9
9
  uploadedAt?: string | null;
10
10
  sha256?: string;
11
11
  }
12
+ /**
13
+ * A blob as the list and get calls return it. Older servers report the size
14
+ * and upload time as `numBytes` and `createdAt`.
15
+ */
16
+ export interface RawBlobItem extends BlobItem {
17
+ numBytes?: number | null;
18
+ createdAt?: string | null;
19
+ }
12
20
  /** Result from a paginated blob list call */
13
21
  export interface BlobListResult {
14
- items: BlobItem[];
22
+ items: RawBlobItem[];
15
23
  cursor?: string;
16
24
  }
@@ -14,21 +14,21 @@ export interface OptimisticListActions<T> {
14
14
  * Optimistically remove item(s) matching `key === value` from the list,
15
15
  * execute the async operation, and rollback on failure.
16
16
  */
17
- optimisticRemove(matchValue: string, operation: () => Promise<void>): Promise<{
17
+ optimisticRemove: (matchValue: string, operation: () => Promise<void>) => Promise<{
18
18
  success: boolean;
19
19
  }>;
20
20
  /**
21
21
  * Optimistically remove multiple items from the list by key values,
22
22
  * execute the async operation, and rollback any that failed.
23
23
  */
24
- optimisticBulkRemove(matchValues: string[], operation: (ids: string[]) => Promise<string[]>): Promise<{
24
+ optimisticBulkRemove: (matchValues: string[], operation: (ids: string[]) => Promise<string[]>) => Promise<{
25
25
  failedIds: string[];
26
26
  }>;
27
27
  /**
28
28
  * Optimistically update a field on an item, execute the async operation,
29
29
  * and rollback on failure.
30
30
  */
31
- optimisticFieldUpdate<K extends keyof T>(matchValue: string, field: K, newValue: T[K], operation: () => Promise<void>): Promise<{
31
+ optimisticFieldUpdate: <K extends keyof T>(matchValue: string, field: K, newValue: T[K], operation: () => Promise<void>) => Promise<{
32
32
  success: boolean;
33
33
  }>;
34
34
  }
@@ -1,5 +1,6 @@
1
1
  import type { FieldSchemaInfo, FilterMode, ModelFilter, ModelInfo, SortDirection, SortField } from "./types";
2
2
  export declare function safeJsonStringify(value: unknown, indent?: number): string;
3
+ export declare function toDisplayString(value: unknown): string;
3
4
  export declare function fuzzyMatch(text: string, query: string): boolean;
4
5
  export declare function filterModeHasValue(mode: FilterMode): boolean;
5
6
  export declare function applyFilterToRecord(record: Record<string, unknown>, filter: ModelFilter): boolean;
@@ -65,6 +65,6 @@ const observer = new MutationObserver(async (mutations, obs) => {
65
65
  });
66
66
 
67
67
  observer.observe(document.body, { childList: true, subtree: true });
68
- `},transformIndexHtml(e){if(!h||!d)return e;let t=`<style data-primitive-devtools-sonner>${g}</style>`;return e.replace(`</body>`,`${t}\n<script type="module" src="/@id/__x00__virtual:primitive-devtools-init"><\/script>\n</body>`)},hotUpdate({file:e,server:t}){if(e.endsWith(`.primitive-test.ts`)){let e=t.moduleGraph.getModuleById(c);e&&(t.moduleGraph.invalidateModule(e),t.ws.send({type:`full-reload`}))}}}}var f=`primitive`,p=`.primitive`,m=`config.json`,h=`local.json`,g=`primitive/config.json`,_=`.primitive/local.json`;function v(e,t){return`Found ${e} but no ${t}: this project still uses the retired layout under ${p}/, which is never read.`}function y(e){return`No ${g} found in ${e} or any parent directory. Primitive commands run inside a Primitive project: it is where the CLI reads the environment, the app that environment names, and the configuration tree from. Run 'primitive init' to create one.`}var b=class extends Error{kind;path;constructor(e,t,n){super(t),this.name=`PrimitiveEnvError`,this.kind=e,this.path=n}};function x(e){if(typeof e!=`string`)return;let t=e.trim();if(!t)return;let n;try{n=new URL(t)}catch{return}if(!(n.protocol!==`https:`&&n.protocol!==`http:`)&&!(n.protocol===`http:`&&n.hostname!==`localhost`&&n.hostname!==`127.0.0.1`)&&!(n.username||n.password)&&!(n.pathname!==`/`&&n.pathname!==``)&&!(n.search||n.hash))return n.origin}function S(e,t){return`Environment "${e}" in ${t?`${g} (${t})`:g} has no "appId". Every environment names exactly one app — add "appId": "<app-id>" to that environment in ${g}. Find the app id in the Primitive admin UI, with 'primitive apps list' run from another Primitive project, or as the residual "currentAppId" in .primitive/credentials.json if this environment was ever pointed at an app by the retired per-machine app selection.`}function C(e){if(typeof e==`string`)return e.trim()||void 0}function w(e){return e.startsWith(`https://`)?`wss://`+e.slice(8):e.startsWith(`http://`)?`ws://`+e.slice(7):e}function T(e={}){let n=(e.env??process.env).PRIMITIVE_PROJECT_CONFIG;if(n){let e=(0,a.resolve)(n);if((0,a.basename)((0,a.dirname)(e))===`.primitive`)throw new b(`stale-layout`,v(e,(0,a.join)((0,a.dirname)((0,a.dirname)(e)),f,m)),e);return(0,t.existsSync)(e)?e:null}let r=(0,a.resolve)(e.cwd??process.cwd());for(;;){let e=(0,a.join)(r,f,m);if((0,t.existsSync)(e))return e;let n=(0,a.join)(r,p,m);if((0,t.existsSync)(n))throw new b(`stale-layout`,v(n,e),n);let i=(0,a.dirname)(r);if(i===r)return null;r=i}}function E(e){let t=(0,a.dirname)(e);return(0,a.basename)(t)===`primitive`?(0,a.dirname)(t):t}function D(e){return(0,a.join)(E(e),p,h)}function O(e){if(!(0,t.existsSync)(e))throw new b(`missing-config`,y((0,a.dirname)(e)),e);let n;try{n=(0,t.readFileSync)(e,`utf-8`)}catch(t){throw new b(`malformed-config`,`Failed to read ${g} (${e}): ${t.message}`,e)}let r;try{r=JSON.parse(n)}catch(t){throw new b(`malformed-config`,`Failed to parse ${g} (${e}): ${t.message}`,e)}if(!r||typeof r!=`object`||Array.isArray(r))throw new b(`malformed-config`,`${g} (${e}) must contain a JSON object at the top level.`,e);let i=r;if(typeof i.version!=`number`||!Number.isInteger(i.version))throw new b(`malformed-config`,`${g} (${e}) is missing required integer field "version".`,e);if(i.version!==1)throw new b(`unsupported-version`,`${g} (${e}) has version ${i.version}, but this tool understands version 1.`,e);if(!i.environments||typeof i.environments!=`object`||Array.isArray(i.environments))throw new b(`malformed-config`,`${g} (${e}) is missing required "environments" object.`,e);let o={};for(let[t,n]of Object.entries(i.environments)){if(!n||typeof n!=`object`||Array.isArray(n))throw new b(`malformed-config`,`Environment "${t}" must be an object in ${g} (${e}).`,e);let r=n;if(typeof r.apiUrl!=`string`||!r.apiUrl)throw new b(`malformed-config`,`Environment "${t}" must have a non-empty "apiUrl" string in ${g} (${e}).`,e);let i=C(r.appId);if(!i)throw new b(`missing-app-id`,S(t,e),e);o[t]={apiUrl:r.apiUrl.replace(/\/$/,``),appId:i,appName:typeof r.appName==`string`?r.appName:void 0,webUrl:x(r.webUrl),description:typeof r.description==`string`?r.description:void 0}}return{version:i.version,defaultEnvironment:typeof i.defaultEnvironment==`string`&&i.defaultEnvironment?i.defaultEnvironment:void 0,environments:o}}function k(e){let n=D(e);if(!(0,t.existsSync)(n))return null;let r=e=>{throw new b(`corrupt-local-state`,`${_} (${n}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`,n)},i;try{i=JSON.parse((0,t.readFileSync)(n,`utf-8`))}catch(e){return r(e.message)}if(!i||typeof i!=`object`||Array.isArray(i))return r(`expected a JSON object`);let a=i.selectedEnvironment;return a==null||a===``?null:typeof a==`string`?a:r(`"selectedEnvironment" must be a string`)}function A(e,t){let n=Object.keys(e.environments),r=n.join(`, `)||`(none)`,i=t.configPath?`${g} (${t.configPath})`:g,a=(n,a,o)=>{if(!e.environments[n])throw new b(`unknown-environment`,`Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`,t.configPath);return{name:n,source:a}};if(t.explicitEnvName)return a(t.explicitEnvName,`explicit`,`explicitly`);if(t.envVarName)return a(t.envVarName,`env-var`,`via PRIMITIVE_ENV`);if(t.localSelection)return a(t.localSelection,`local`,`in ${_}`);if(e.defaultEnvironment)return a(e.defaultEnvironment,`default`,`as "defaultEnvironment"`);if(n.length===1)return{name:n[0],source:`sole`};throw n.length===0?new b(`no-selection`,`${i} has no environments defined. Run 'primitive env add <name>' or 'primitive init'.`,t.configPath):new b(`no-selection`,`No environment selected. Run 'primitive env use <name>', set "defaultEnvironment" in ${i}, or export PRIMITIVE_ENV. Available: ${r}`,t.configPath)}function j(e={}){let t=e.env??process.env,n=e.configPath??T({cwd:e.cwd,env:t});if(!n)throw new b(`missing-config`,y(e.cwd??process.cwd()));let r=E(n),i=O(n),{name:a,source:o}=A(i,{explicitEnvName:e.explicitEnvName||null,envVarName:t.PRIMITIVE_ENV||null,localSelection:k(n),configPath:n}),s=i.environments[a];return{name:a,apiUrl:s.apiUrl,wsUrl:w(s.apiUrl),appId:s.appId,appName:s.appName,webUrl:s.webUrl,description:s.description,source:o,configPath:n,localStatePath:D(n),projectRoot:r}}var M=[`VITE_APP_ID`,`VITE_API_URL`,`VITE_WS_URL`,`VITE_APP_NAME`],N=`VITE_EXPECTED_PRIMITIVE_ENV`,P=new Map;function F(e,t){let n=process.env[e];n!==void 0&&n!==``&&P.get(e)!==n||(process.env[e]=t,P.set(e,t))}function I(e={}){return j({cwd:e.root,env:e.env,explicitEnvName:e.primitiveEnv??null})}function L(e,t,n){let r=e=>n.includes(e)?` (overridden)`:``,i=[`[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,`[primitive-env] apiUrl: ${t.apiUrl}${r(`VITE_API_URL`)}`,`[primitive-env] wsUrl: ${t.wsUrl}${r(`VITE_WS_URL`)}`,`[primitive-env] appId: ${t.appId??`(unset)`}${r(`VITE_APP_ID`)}`,`[primitive-env] appName: ${t.appName??`(unset)`}${r(`VITE_APP_NAME`)}`,`[primitive-env] config: ${e.configPath}`];return n.length>0&&i.push(`[primitive-env] overridden by the environment: ${n.join(`, `)}`),i.join(`
69
- `)}function R(e,t){let n=e?.envDir;return n===!1?null:typeof n==`string`&&n!==``?(0,a.resolve)(t,n):t}function z(e,t){let n=process.env[N];if(n!==void 0&&n!==``)return{value:n,where:`the process environment`};if(t===null)return null;for(let n of[`.env.${e}.local`,`.env.${e}`,`.env.local`,`.env`]){let e=W((0,a.join)(t,n))[N];if(e!==void 0)return{value:e,where:n}}return null}function B(e,t,n){return[`[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,`[primitive-env] expected: ${t.value} (${N} in ${t.where})`,`[primitive-env] resolved: ${n.name} (selected: ${n.source})`,`[primitive-env] config: ${n.configPath}`,``,`Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${N} in ${t.where}.`,``,`A mode declares this when its .env.${e} carries values coupled to one backend, so continuing would run this environment's identity with another's configuration.`].join(`
70
- `)}function V(e,t,n){let r=z(e,t);if(r&&r.value!==``&&r.value!==n.name)throw Error(B(e,r,n))}function H(e={}){let t=null,n=null,r,i=[],a=!1,o=null;return{name:`primitive-env`,enforce:`pre`,config(s,c){a=c?.command===`serve`,o=null;let l=s?.root??process.cwd(),u=c?.mode??`development`,d=U(u,l),f={};for(let e of M){let t=process.env[e],n=t!==void 0&&P.get(e)!==t?t:d[e];n!==void 0&&n!==``&&(f[e]=n)}let p;try{p=j({cwd:l,explicitEnvName:e.primitiveEnv??null})}catch(e){if(e instanceof b&&e.kind===`missing-config`&&f.VITE_APP_ID&&f.VITE_API_URL)return console.warn(`[primitive-env] No primitive/config.json found; using VITE_APP_ID / VITE_API_URL from the environment. Run 'primitive init' to make the project the source of truth.`),r=f.VITE_APP_NAME,{};throw e}if(!(f.VITE_APP_ID&&f.VITE_API_URL)){let e=R(s,l);V(u,e,p),o={root:l,mode:u,dir:e}}t=p,r=f.VITE_APP_NAME??p.appName;let m={VITE_APP_ID:p.appId,VITE_API_URL:p.apiUrl,VITE_WS_URL:p.wsUrl,VITE_APP_NAME:p.appName},h={"import.meta.env.VITE_PRIMITIVE_ENV":JSON.stringify(p.name)},g=[];for(let e of M){if(f[e]!==void 0){g.push(e);continue}let t=m[e];t!==void 0&&(h[`import.meta.env.${e}`]=JSON.stringify(t),F(e,t))}return F(`VITE_PRIMITIVE_ENV`,p.name),i=g,n={apiUrl:f.VITE_API_URL??p.apiUrl,wsUrl:f.VITE_WS_URL??p.wsUrl,appId:f.VITE_APP_ID??p.appId,appName:r},e.logResolved!==!1&&console.log(L(p,n,g)),g.length>0&&console.warn(`[primitive-env] Overridden by an explicit value in .env or the shell: ${g.join(`, `)}. Remove it to use primitive/config.json (deploys reject these outright).`),{define:h}},configResolved(e){if(!o||!t)return;let n=R(e,o.root),r=e?.mode??o.mode;n===o.dir&&r===o.mode||(V(r,n,t),o={root:o.root,mode:r,dir:n})},transformIndexHtml(){if(!a||!t||!n)return[];let e=`%c[primitive] env=${t.name} api=${n.apiUrl} app=${n.appId??`(unset)`} (${t.configPath})`+(i.length>0?` overridden: ${i.join(`, `)}`:``);return[{tag:`script`,injectTo:`head`,children:`console.info(${JSON.stringify(e)}, "color:#888");`}]},appName(){return r},resolved(){return t}}}function U(e,t){let n=[`.env`,`.env.local`,`.env.${e}`,`.env.${e}.local`],r={};for(let e of n)Object.assign(r,W((0,a.join)(t,e)));return r}function W(e){if(!(0,t.existsSync)(e))return{};let n={};for(let r of(0,t.readFileSync)(e,`utf-8`).split(/\r?\n/)){let e=r.trim();if(!e||e.startsWith(`#`))continue;let t=e.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!t)continue;let i=t[2].trim(),a=i[0],o=a===`"`||a===`'`||a==="`"?i.indexOf(a,1):-1;n[t[1]]=o===-1?i.replace(/\s+#.*$/,``).trim():i.slice(1,o)}return n}exports.PrimitiveEnvError=b,exports.primitiveDevTools=d,exports.primitiveEnv=H,exports.resolvePrimitiveEnv=I;
68
+ `},transformIndexHtml(e){if(!h||!d)return e;let t=`<style data-primitive-devtools-sonner>${g}</style>`;return e.replace(`</body>`,`${t}\n<script type="module" src="/@id/__x00__virtual:primitive-devtools-init"><\/script>\n</body>`)},hotUpdate({file:e,server:t}){if(e.endsWith(`.primitive-test.ts`)){let e=t.moduleGraph.getModuleById(c);e&&(t.moduleGraph.invalidateModule(e),t.ws.send({type:`full-reload`}))}}}}var f=`primitive`,p=`.primitive`,m=`config.json`,h=`local.json`,g=`primitive/config.json`,_=`.primitive/local.json`;function v(e,t){return`Found ${e} but no ${t}: this project still uses the retired layout under ${p}/, which is never read.`}function y(e){return`No ${g} found in ${e} or any parent directory. Primitive commands run inside a Primitive project: it is where the CLI reads the environment, the app that environment names, and the configuration tree from. Run 'primitive init' to create one.`}var b=class extends Error{kind;path;constructor(e,t,n){super(t),this.name=`PrimitiveEnvError`,this.kind=e,this.path=n}};function x(e){if(typeof e!=`string`)return;let t=e.trim();if(!t)return;let n;try{n=new URL(t)}catch{return}if(!(n.protocol!==`https:`&&n.protocol!==`http:`)&&!(n.protocol===`http:`&&n.hostname!==`localhost`&&n.hostname!==`127.0.0.1`)&&!(n.username||n.password)&&!(n.pathname!==`/`&&n.pathname!==``)&&!(n.search||n.hash))return n.origin}function S(e,t){return`Environment "${e}" in ${t?`${g} (${t})`:g} has no "appId". Every environment names exactly one app — add "appId": "<app-id>" to that environment in ${g}. Find the app id in the Primitive admin UI, with 'primitive apps list' run from another Primitive project, or as the residual "currentAppId" in .primitive/credentials.json if this environment was ever pointed at an app by the retired per-machine app selection.`}function C(e){if(typeof e==`string`)return e.trim()||void 0}function w(e){return e.startsWith(`https://`)?`wss://`+e.slice(8):e.startsWith(`http://`)?`ws://`+e.slice(7):e}function T(e={}){let n=(e.env??process.env).PRIMITIVE_PROJECT_CONFIG;if(n){let e=(0,a.resolve)(n);if((0,a.basename)((0,a.dirname)(e))===`.primitive`)throw new b(`stale-layout`,v(e,(0,a.join)((0,a.dirname)((0,a.dirname)(e)),f,m)),e);return(0,t.existsSync)(e)?e:null}let r=(0,a.resolve)(e.cwd??process.cwd());for(;;){let e=(0,a.join)(r,f,m);if((0,t.existsSync)(e))return e;let n=(0,a.join)(r,p,m);if((0,t.existsSync)(n))throw new b(`stale-layout`,v(n,e),n);let i=(0,a.dirname)(r);if(i===r)return null;r=i}}function E(e){let t=(0,a.dirname)(e);return(0,a.basename)(t)===`primitive`?(0,a.dirname)(t):t}function D(e){return(0,a.join)(E(e),p,h)}function O(e){return e instanceof Error?e.message:String(e)}function k(e){if(!(0,t.existsSync)(e))throw new b(`missing-config`,y((0,a.dirname)(e)),e);let n;try{n=(0,t.readFileSync)(e,`utf-8`)}catch(t){throw new b(`malformed-config`,`Failed to read ${g} (${e}): ${O(t)}`,e)}let r;try{r=JSON.parse(n)}catch(t){throw new b(`malformed-config`,`Failed to parse ${g} (${e}): ${O(t)}`,e)}if(!r||typeof r!=`object`||Array.isArray(r))throw new b(`malformed-config`,`${g} (${e}) must contain a JSON object at the top level.`,e);let i=r;if(typeof i.version!=`number`||!Number.isInteger(i.version))throw new b(`malformed-config`,`${g} (${e}) is missing required integer field "version".`,e);if(i.version!==1)throw new b(`unsupported-version`,`${g} (${e}) has version ${i.version}, but this tool understands version 1.`,e);if(!i.environments||typeof i.environments!=`object`||Array.isArray(i.environments))throw new b(`malformed-config`,`${g} (${e}) is missing required "environments" object.`,e);let o={};for(let[t,n]of Object.entries(i.environments)){if(!n||typeof n!=`object`||Array.isArray(n))throw new b(`malformed-config`,`Environment "${t}" must be an object in ${g} (${e}).`,e);let r=n;if(typeof r.apiUrl!=`string`||!r.apiUrl)throw new b(`malformed-config`,`Environment "${t}" must have a non-empty "apiUrl" string in ${g} (${e}).`,e);let i=C(r.appId);if(!i)throw new b(`missing-app-id`,S(t,e),e);o[t]={apiUrl:r.apiUrl.replace(/\/$/,``),appId:i,appName:typeof r.appName==`string`?r.appName:void 0,webUrl:x(r.webUrl),description:typeof r.description==`string`?r.description:void 0}}return{version:i.version,defaultEnvironment:typeof i.defaultEnvironment==`string`&&i.defaultEnvironment?i.defaultEnvironment:void 0,environments:o}}function A(e){let n=D(e);if(!(0,t.existsSync)(n))return null;let r=e=>{throw new b(`corrupt-local-state`,`${_} (${n}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`,n)},i;try{i=JSON.parse((0,t.readFileSync)(n,`utf-8`))}catch(e){return r(O(e))}if(!i||typeof i!=`object`||Array.isArray(i))return r(`expected a JSON object`);let a=i.selectedEnvironment;return a==null||a===``?null:typeof a==`string`?a:r(`"selectedEnvironment" must be a string`)}function j(e,t){let n=Object.keys(e.environments),r=n.join(`, `)||`(none)`,i=t.configPath?`${g} (${t.configPath})`:g,a=(n,a,o)=>{if(!e.environments[n])throw new b(`unknown-environment`,`Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`,t.configPath);return{name:n,source:a}};if(t.explicitEnvName)return a(t.explicitEnvName,`explicit`,`explicitly`);if(t.envVarName)return a(t.envVarName,`env-var`,`via PRIMITIVE_ENV`);if(t.localSelection)return a(t.localSelection,`local`,`in ${_}`);if(e.defaultEnvironment)return a(e.defaultEnvironment,`default`,`as "defaultEnvironment"`);if(n.length===1)return{name:n[0],source:`sole`};throw n.length===0?new b(`no-selection`,`${i} has no environments defined. Run 'primitive env add <name>' or 'primitive init'.`,t.configPath):new b(`no-selection`,`No environment selected. Run 'primitive env use <name>', set "defaultEnvironment" in ${i}, or export PRIMITIVE_ENV. Available: ${r}`,t.configPath)}function M(e={}){let t=e.env??process.env,n=e.configPath??T({cwd:e.cwd,env:t});if(!n)throw new b(`missing-config`,y(e.cwd??process.cwd()));let r=E(n),i=k(n),{name:a,source:o}=j(i,{explicitEnvName:e.explicitEnvName||null,envVarName:t.PRIMITIVE_ENV||null,localSelection:A(n),configPath:n}),s=i.environments[a];return{name:a,apiUrl:s.apiUrl,wsUrl:w(s.apiUrl),appId:s.appId,appName:s.appName,webUrl:s.webUrl,description:s.description,source:o,configPath:n,localStatePath:D(n),projectRoot:r}}var N=[`VITE_APP_ID`,`VITE_API_URL`,`VITE_WS_URL`,`VITE_APP_NAME`],P=`VITE_EXPECTED_PRIMITIVE_ENV`,F=new Map;function I(e,t){let n=process.env[e];n!==void 0&&n!==``&&F.get(e)!==n||(process.env[e]=t,F.set(e,t))}function L(e={}){return M({cwd:e.root,env:e.env,explicitEnvName:e.primitiveEnv??null})}function R(e,t,n){let r=e=>n.includes(e)?` (overridden)`:``,i=[`[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,`[primitive-env] apiUrl: ${t.apiUrl}${r(`VITE_API_URL`)}`,`[primitive-env] wsUrl: ${t.wsUrl}${r(`VITE_WS_URL`)}`,`[primitive-env] appId: ${t.appId??`(unset)`}${r(`VITE_APP_ID`)}`,`[primitive-env] appName: ${t.appName??`(unset)`}${r(`VITE_APP_NAME`)}`,`[primitive-env] config: ${e.configPath}`];return n.length>0&&i.push(`[primitive-env] overridden by the environment: ${n.join(`, `)}`),i.join(`
69
+ `)}function z(e,t){let n=e?.envDir;return n===!1?null:typeof n==`string`&&n!==``?(0,a.resolve)(t,n):t}function B(e,t){let n=process.env[P];if(n!==void 0&&n!==``)return{value:n,where:`the process environment`};if(t===null)return null;for(let n of[`.env.${e}.local`,`.env.${e}`,`.env.local`,`.env`]){let e=G((0,a.join)(t,n))[P];if(e!==void 0)return{value:e,where:n}}return null}function V(e,t,n){return[`[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,`[primitive-env] expected: ${t.value} (${P} in ${t.where})`,`[primitive-env] resolved: ${n.name} (selected: ${n.source})`,`[primitive-env] config: ${n.configPath}`,``,`Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${P} in ${t.where}.`,``,`A mode declares this when its .env.${e} carries values coupled to one backend, so continuing would run this environment's identity with another's configuration.`].join(`
70
+ `)}function H(e,t,n){let r=B(e,t);if(r&&r.value!==``&&r.value!==n.name)throw Error(V(e,r,n))}function U(e={}){let t=null,n=null,r,i=[],a=!1,o=null;return{name:`primitive-env`,enforce:`pre`,config(s,c){a=c?.command===`serve`,o=null;let l=s?.root??process.cwd(),u=c?.mode??`development`,d=W(u,l),f={};for(let e of N){let t=process.env[e],n=t!==void 0&&F.get(e)!==t?t:d[e];n!==void 0&&n!==``&&(f[e]=n)}let p;try{p=M({cwd:l,explicitEnvName:e.primitiveEnv??null})}catch(e){if(e instanceof b&&e.kind===`missing-config`&&f.VITE_APP_ID&&f.VITE_API_URL)return console.warn(`[primitive-env] No primitive/config.json found; using VITE_APP_ID / VITE_API_URL from the environment. Run 'primitive init' to make the project the source of truth.`),r=f.VITE_APP_NAME,{};throw e}if(!(f.VITE_APP_ID&&f.VITE_API_URL)){let e=z(s,l);H(u,e,p),o={root:l,mode:u,dir:e}}t=p,r=f.VITE_APP_NAME??p.appName;let m={VITE_APP_ID:p.appId,VITE_API_URL:p.apiUrl,VITE_WS_URL:p.wsUrl,VITE_APP_NAME:p.appName},h={"import.meta.env.VITE_PRIMITIVE_ENV":JSON.stringify(p.name)},g=[];for(let e of N){if(f[e]!==void 0){g.push(e);continue}let t=m[e];t!==void 0&&(h[`import.meta.env.${e}`]=JSON.stringify(t),I(e,t))}return I(`VITE_PRIMITIVE_ENV`,p.name),i=g,n={apiUrl:f.VITE_API_URL??p.apiUrl,wsUrl:f.VITE_WS_URL??p.wsUrl,appId:f.VITE_APP_ID??p.appId,appName:r},e.logResolved!==!1&&console.log(R(p,n,g)),g.length>0&&console.warn(`[primitive-env] Overridden by an explicit value in .env or the shell: ${g.join(`, `)}. Remove it to use primitive/config.json (deploys reject these outright).`),{define:h}},configResolved(e){if(!o||!t)return;let n=z(e,o.root),r=e?.mode??o.mode;n===o.dir&&r===o.mode||(H(r,n,t),o={root:o.root,mode:r,dir:n})},transformIndexHtml(){if(!a||!t||!n)return[];let e=`%c[primitive] env=${t.name} api=${n.apiUrl} app=${n.appId??`(unset)`} (${t.configPath})`+(i.length>0?` overridden: ${i.join(`, `)}`:``);return[{tag:`script`,injectTo:`head`,children:`console.info(${JSON.stringify(e)}, "color:#888");`}]},appName(){return r},resolved(){return t}}}function W(e,t){let n=[`.env`,`.env.local`,`.env.${e}`,`.env.${e}.local`],r={};for(let e of n)Object.assign(r,G((0,a.join)(t,e)));return r}function G(e){if(!(0,t.existsSync)(e))return{};let n={};for(let r of(0,t.readFileSync)(e,`utf-8`).split(/\r?\n/)){let e=r.trim();if(!e||e.startsWith(`#`))continue;let t=e.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!t)continue;let i=t[2].trim(),a=i[0],o=a===`"`||a===`'`||a==="`"?i.indexOf(a,1):-1;n[t[1]]=o===-1?i.replace(/\s+#.*$/,``).trim():i.slice(1,o)}return n}exports.PrimitiveEnvError=b,exports.primitiveDevTools=d,exports.primitiveEnv=U,exports.resolvePrimitiveEnv=L;
@@ -123,19 +123,22 @@ function k(e) {
123
123
  function A(e) {
124
124
  return s(k(e), g, v);
125
125
  }
126
- function j(n) {
126
+ function j(e) {
127
+ return e instanceof Error ? e.message : String(e);
128
+ }
129
+ function M(n) {
127
130
  if (!e(n)) throw new C("missing-config", S(o(n)), n);
128
131
  let r;
129
132
  try {
130
133
  r = t(n, "utf-8");
131
134
  } catch (e) {
132
- throw new C("malformed-config", `Failed to read ${y} (${n}): ${e.message}`, n);
135
+ throw new C("malformed-config", `Failed to read ${y} (${n}): ${j(e)}`, n);
133
136
  }
134
137
  let i;
135
138
  try {
136
139
  i = JSON.parse(r);
137
140
  } catch (e) {
138
- throw new C("malformed-config", `Failed to parse ${y} (${n}): ${e.message}`, n);
141
+ throw new C("malformed-config", `Failed to parse ${y} (${n}): ${j(e)}`, n);
139
142
  }
140
143
  if (!i || typeof i != "object" || Array.isArray(i)) throw new C("malformed-config", `${y} (${n}) must contain a JSON object at the top level.`, n);
141
144
  let a = i;
@@ -163,7 +166,7 @@ function j(n) {
163
166
  environments: s
164
167
  };
165
168
  }
166
- function M(n) {
169
+ function N(n) {
167
170
  let r = A(n);
168
171
  if (!e(r)) return null;
169
172
  let i = (e) => {
@@ -172,13 +175,13 @@ function M(n) {
172
175
  try {
173
176
  a = JSON.parse(t(r, "utf-8"));
174
177
  } catch (e) {
175
- return i(e.message);
178
+ return i(j(e));
176
179
  }
177
180
  if (!a || typeof a != "object" || Array.isArray(a)) return i("expected a JSON object");
178
181
  let o = a.selectedEnvironment;
179
182
  return o == null || o === "" ? null : typeof o == "string" ? o : i("\"selectedEnvironment\" must be a string");
180
183
  }
181
- function N(e, t) {
184
+ function P(e, t) {
182
185
  let n = Object.keys(e.environments), r = n.join(", ") || "(none)", i = t.configPath ? `${y} (${t.configPath})` : y, a = (n, a, o) => {
183
186
  if (!e.environments[n]) throw new C("unknown-environment", `Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`, t.configPath);
184
187
  return {
@@ -196,16 +199,16 @@ function N(e, t) {
196
199
  };
197
200
  throw n.length === 0 ? new C("no-selection", `${i} has no environments defined. Run 'primitive env add <name>' or 'primitive init'.`, t.configPath) : new C("no-selection", `No environment selected. Run 'primitive env use <name>', set "defaultEnvironment" in ${i}, or export PRIMITIVE_ENV. Available: ${r}`, t.configPath);
198
201
  }
199
- function P(e = {}) {
202
+ function F(e = {}) {
200
203
  let t = e.env ?? process.env, n = e.configPath ?? O({
201
204
  cwd: e.cwd,
202
205
  env: t
203
206
  });
204
207
  if (!n) throw new C("missing-config", S(e.cwd ?? process.cwd()));
205
- let r = k(n), i = j(n), { name: a, source: o } = N(i, {
208
+ let r = k(n), i = M(n), { name: a, source: o } = P(i, {
206
209
  explicitEnvName: e.explicitEnvName || null,
207
210
  envVarName: t.PRIMITIVE_ENV || null,
208
- localSelection: M(n),
211
+ localSelection: N(n),
209
212
  configPath: n
210
213
  }), s = i.environments[a];
211
214
  return {
@@ -224,24 +227,24 @@ function P(e = {}) {
224
227
  }
225
228
  //#endregion
226
229
  //#region src/dev-tools/vite-plugin/primitive-env.ts
227
- var F = [
230
+ var I = [
228
231
  "VITE_APP_ID",
229
232
  "VITE_API_URL",
230
233
  "VITE_WS_URL",
231
234
  "VITE_APP_NAME"
232
- ], I = "VITE_EXPECTED_PRIMITIVE_ENV", L = /* @__PURE__ */ new Map();
233
- function R(e, t) {
235
+ ], L = "VITE_EXPECTED_PRIMITIVE_ENV", R = /* @__PURE__ */ new Map();
236
+ function z(e, t) {
234
237
  let n = process.env[e];
235
- n !== void 0 && n !== "" && L.get(e) !== n || (process.env[e] = t, L.set(e, t));
238
+ n !== void 0 && n !== "" && R.get(e) !== n || (process.env[e] = t, R.set(e, t));
236
239
  }
237
- function z(e = {}) {
238
- return P({
240
+ function B(e = {}) {
241
+ return F({
239
242
  cwd: e.root,
240
243
  env: e.env,
241
244
  explicitEnvName: e.primitiveEnv ?? null
242
245
  });
243
246
  }
244
- function B(e, t, n) {
247
+ function V(e, t, n) {
245
248
  let r = (e) => n.includes(e) ? " (overridden)" : "", i = [
246
249
  `[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,
247
250
  `[primitive-env] apiUrl: ${t.apiUrl}${r("VITE_API_URL")}`,
@@ -252,12 +255,12 @@ function B(e, t, n) {
252
255
  ];
253
256
  return n.length > 0 && i.push(`[primitive-env] overridden by the environment: ${n.join(", ")}`), i.join("\n");
254
257
  }
255
- function V(e, t) {
258
+ function H(e, t) {
256
259
  let n = e?.envDir;
257
260
  return n === !1 ? null : typeof n == "string" && n !== "" ? c(t, n) : t;
258
261
  }
259
- function H(e, t) {
260
- let n = process.env[I];
262
+ function U(e, t) {
263
+ let n = process.env[L];
261
264
  if (n !== void 0 && n !== "") return {
262
265
  value: n,
263
266
  where: "the process environment"
@@ -269,7 +272,7 @@ function H(e, t) {
269
272
  ".env.local",
270
273
  ".env"
271
274
  ]) {
272
- let e = q(s(t, n))[I];
275
+ let e = J(s(t, n))[L];
273
276
  if (e !== void 0) return {
274
277
  value: e,
275
278
  where: n
@@ -277,37 +280,37 @@ function H(e, t) {
277
280
  }
278
281
  return null;
279
282
  }
280
- function U(e, t, n) {
283
+ function W(e, t, n) {
281
284
  return [
282
285
  `[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,
283
- `[primitive-env] expected: ${t.value} (${I} in ${t.where})`,
286
+ `[primitive-env] expected: ${t.value} (${L} in ${t.where})`,
284
287
  `[primitive-env] resolved: ${n.name} (selected: ${n.source})`,
285
288
  `[primitive-env] config: ${n.configPath}`,
286
289
  "",
287
- `Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${I} in ${t.where}.`,
290
+ `Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${L} in ${t.where}.`,
288
291
  "",
289
292
  `A mode declares this when its .env.${e} carries values coupled to one backend, so continuing would run this environment's identity with another's configuration.`
290
293
  ].join("\n");
291
294
  }
292
- function W(e, t, n) {
293
- let r = H(e, t);
294
- if (r && r.value !== "" && r.value !== n.name) throw Error(U(e, r, n));
295
+ function G(e, t, n) {
296
+ let r = U(e, t);
297
+ if (r && r.value !== "" && r.value !== n.name) throw Error(W(e, r, n));
295
298
  }
296
- function G(e = {}) {
299
+ function K(e = {}) {
297
300
  let t = null, n = null, r, i = [], a = !1, o = null;
298
301
  return {
299
302
  name: "primitive-env",
300
303
  enforce: "pre",
301
304
  config(s, c) {
302
305
  a = c?.command === "serve", o = null;
303
- let l = s?.root ?? process.cwd(), u = c?.mode ?? "development", d = K(u, l), f = {};
304
- for (let e of F) {
305
- let t = process.env[e], n = t !== void 0 && L.get(e) !== t ? t : d[e];
306
+ let l = s?.root ?? process.cwd(), u = c?.mode ?? "development", d = q(u, l), f = {};
307
+ for (let e of I) {
308
+ let t = process.env[e], n = t !== void 0 && R.get(e) !== t ? t : d[e];
306
309
  n !== void 0 && n !== "" && (f[e] = n);
307
310
  }
308
311
  let p;
309
312
  try {
310
- p = P({
313
+ p = F({
311
314
  cwd: l,
312
315
  explicitEnvName: e.primitiveEnv ?? null
313
316
  });
@@ -316,8 +319,8 @@ function G(e = {}) {
316
319
  throw e;
317
320
  }
318
321
  if (!(f.VITE_APP_ID && f.VITE_API_URL)) {
319
- let e = V(s, l);
320
- W(u, e, p), o = {
322
+ let e = H(s, l);
323
+ G(u, e, p), o = {
321
324
  root: l,
322
325
  mode: u,
323
326
  dir: e
@@ -330,25 +333,25 @@ function G(e = {}) {
330
333
  VITE_WS_URL: p.wsUrl,
331
334
  VITE_APP_NAME: p.appName
332
335
  }, h = { "import.meta.env.VITE_PRIMITIVE_ENV": JSON.stringify(p.name) }, g = [];
333
- for (let e of F) {
336
+ for (let e of I) {
334
337
  if (f[e] !== void 0) {
335
338
  g.push(e);
336
339
  continue;
337
340
  }
338
341
  let t = m[e];
339
- t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t), R(e, t));
342
+ t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t), z(e, t));
340
343
  }
341
- return R("VITE_PRIMITIVE_ENV", p.name), i = g, n = {
344
+ return z("VITE_PRIMITIVE_ENV", p.name), i = g, n = {
342
345
  apiUrl: f.VITE_API_URL ?? p.apiUrl,
343
346
  wsUrl: f.VITE_WS_URL ?? p.wsUrl,
344
347
  appId: f.VITE_APP_ID ?? p.appId,
345
348
  appName: r
346
- }, e.logResolved !== !1 && console.log(B(p, n, g)), g.length > 0 && console.warn(`[primitive-env] Overridden by an explicit value in .env or the shell: ${g.join(", ")}. Remove it to use primitive/config.json (deploys reject these outright).`), { define: h };
349
+ }, e.logResolved !== !1 && console.log(V(p, n, g)), g.length > 0 && console.warn(`[primitive-env] Overridden by an explicit value in .env or the shell: ${g.join(", ")}. Remove it to use primitive/config.json (deploys reject these outright).`), { define: h };
347
350
  },
348
351
  configResolved(e) {
349
352
  if (!o || !t) return;
350
- let n = V(e, o.root), r = e?.mode ?? o.mode;
351
- n === o.dir && r === o.mode || (W(r, n, t), o = {
353
+ let n = H(e, o.root), r = e?.mode ?? o.mode;
354
+ n === o.dir && r === o.mode || (G(r, n, t), o = {
352
355
  root: o.root,
353
356
  mode: r,
354
357
  dir: n
@@ -371,17 +374,17 @@ function G(e = {}) {
371
374
  }
372
375
  };
373
376
  }
374
- function K(e, t) {
377
+ function q(e, t) {
375
378
  let n = [
376
379
  ".env",
377
380
  ".env.local",
378
381
  `.env.${e}`,
379
382
  `.env.${e}.local`
380
383
  ], r = {};
381
- for (let e of n) Object.assign(r, q(s(t, e)));
384
+ for (let e of n) Object.assign(r, J(s(t, e)));
382
385
  return r;
383
386
  }
384
- function q(n) {
387
+ function J(n) {
385
388
  if (!e(n)) return {};
386
389
  let r = {};
387
390
  for (let e of t(n, "utf-8").split(/\r?\n/)) {
@@ -395,4 +398,4 @@ function q(n) {
395
398
  return r;
396
399
  }
397
400
  //#endregion
398
- export { C as PrimitiveEnvError, m as primitiveDevTools, G as primitiveEnv, z as resolvePrimitiveEnv };
401
+ export { C as PrimitiveEnvError, m as primitiveDevTools, K as primitiveEnv, B as resolvePrimitiveEnv };