primitive-app 3.1.0 → 3.1.2

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.
@@ -63,93 +63,127 @@ export const keyboardShortcut = ${JSON.stringify(s)};
63
63
  }
64
64
  };
65
65
  }
66
- var h = ".primitive", g = "config.json", _ = "local.json", v = ".primitive/config.json", y = ".primitive/local.json", b = class extends Error {
66
+ var h = "primitive", g = ".primitive", _ = "config.json", v = "local.json", y = "primitive/config.json", b = ".primitive/local.json";
67
+ function x(e, t) {
68
+ return `Found ${e} but no ${t}: this project still uses the retired layout under ${g}/, which is never read.`;
69
+ }
70
+ function S(e) {
71
+ return `No ${y} 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.`;
72
+ }
73
+ var C = class extends Error {
67
74
  kind;
68
75
  path;
69
76
  constructor(e, t, n) {
70
77
  super(t), this.name = "PrimitiveEnvError", this.kind = e, this.path = n;
71
78
  }
72
79
  };
73
- function x(e) {
80
+ function w(e) {
81
+ if (typeof e != "string") return;
82
+ let t = e.trim();
83
+ if (!t) return;
84
+ let n;
85
+ try {
86
+ n = new URL(t);
87
+ } catch {
88
+ return;
89
+ }
90
+ 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;
91
+ }
92
+ function T(e, t) {
93
+ return `Environment "${e}" in ${t ? `${y} (${t})` : y} has no "appId". Every environment names exactly one app — add "appId": "<app-id>" to that environment in ${y}. 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.`;
94
+ }
95
+ function E(e) {
96
+ if (typeof e == "string") return e.trim() || void 0;
97
+ }
98
+ function D(e) {
74
99
  return e.startsWith("https://") ? "wss://" + e.slice(8) : e.startsWith("http://") ? "ws://" + e.slice(7) : e;
75
100
  }
76
- function S(t = {}) {
101
+ function O(t = {}) {
77
102
  let n = (t.env ?? process.env).PRIMITIVE_PROJECT_CONFIG;
78
103
  if (n) {
79
104
  let t = c(n);
105
+ if (a(o(t)) === ".primitive") throw new C("stale-layout", x(t, s(o(o(t)), h, _)), t);
80
106
  return e(t) ? t : null;
81
107
  }
82
108
  let r = c(t.cwd ?? process.cwd());
83
109
  for (;;) {
84
- let t = s(r, h, g);
110
+ let t = s(r, h, _);
85
111
  if (e(t)) return t;
86
- let n = o(r);
87
- if (n === r) return null;
88
- r = n;
112
+ let n = s(r, g, _);
113
+ if (e(n)) throw new C("stale-layout", x(n, t), n);
114
+ let i = o(r);
115
+ if (i === r) return null;
116
+ r = i;
89
117
  }
90
118
  }
91
- function C(e) {
119
+ function k(e) {
92
120
  let t = o(e);
93
- return a(t) === ".primitive" ? o(t) : t;
121
+ return a(t) === "primitive" ? o(t) : t;
94
122
  }
95
- function w(e) {
96
- return s(o(e), _);
123
+ function A(e) {
124
+ return s(k(e), g, v);
125
+ }
126
+ function j(e) {
127
+ return e instanceof Error ? e.message : String(e);
97
128
  }
98
- function T(n) {
99
- if (!e(n)) throw new b("missing-config", `No ${v} found at ${n}. Run 'primitive init' to create one.`, n);
129
+ function M(n) {
130
+ if (!e(n)) throw new C("missing-config", S(o(n)), n);
100
131
  let r;
101
132
  try {
102
133
  r = t(n, "utf-8");
103
134
  } catch (e) {
104
- throw new b("malformed-config", `Failed to read ${v} (${n}): ${e.message}`, n);
135
+ throw new C("malformed-config", `Failed to read ${y} (${n}): ${j(e)}`, n);
105
136
  }
106
137
  let i;
107
138
  try {
108
139
  i = JSON.parse(r);
109
140
  } catch (e) {
110
- throw new b("malformed-config", `Failed to parse ${v} (${n}): ${e.message}`, n);
141
+ throw new C("malformed-config", `Failed to parse ${y} (${n}): ${j(e)}`, n);
111
142
  }
112
- if (!i || typeof i != "object" || Array.isArray(i)) throw new b("malformed-config", `${v} (${n}) must contain a JSON object at the top level.`, n);
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);
113
144
  let a = i;
114
- if (typeof a.version != "number" || !Number.isInteger(a.version)) throw new b("malformed-config", `${v} (${n}) is missing required integer field "version".`, n);
115
- if (a.version !== 1) throw new b("unsupported-version", `${v} (${n}) has version ${a.version}, but this tool understands version 1.`, n);
116
- if (!a.environments || typeof a.environments != "object" || Array.isArray(a.environments)) throw new b("malformed-config", `${v} (${n}) is missing required "environments" object.`, n);
117
- let o = {};
145
+ if (typeof a.version != "number" || !Number.isInteger(a.version)) throw new C("malformed-config", `${y} (${n}) is missing required integer field "version".`, n);
146
+ if (a.version !== 1) throw new C("unsupported-version", `${y} (${n}) has version ${a.version}, but this tool understands version 1.`, n);
147
+ if (!a.environments || typeof a.environments != "object" || Array.isArray(a.environments)) throw new C("malformed-config", `${y} (${n}) is missing required "environments" object.`, n);
148
+ let s = {};
118
149
  for (let [e, t] of Object.entries(a.environments)) {
119
- if (!t || typeof t != "object" || Array.isArray(t)) throw new b("malformed-config", `Environment "${e}" must be an object in ${v} (${n}).`, n);
150
+ if (!t || typeof t != "object" || Array.isArray(t)) throw new C("malformed-config", `Environment "${e}" must be an object in ${y} (${n}).`, n);
120
151
  let r = t;
121
- if (typeof r.apiUrl != "string" || !r.apiUrl) throw new b("malformed-config", `Environment "${e}" must have a non-empty "apiUrl" string in ${v} (${n}).`, n);
122
- o[e] = {
152
+ if (typeof r.apiUrl != "string" || !r.apiUrl) throw new C("malformed-config", `Environment "${e}" must have a non-empty "apiUrl" string in ${y} (${n}).`, n);
153
+ let i = E(r.appId);
154
+ if (!i) throw new C("missing-app-id", T(e, n), n);
155
+ s[e] = {
123
156
  apiUrl: r.apiUrl.replace(/\/$/, ""),
124
- appId: typeof r.appId == "string" ? r.appId : void 0,
157
+ appId: i,
125
158
  appName: typeof r.appName == "string" ? r.appName : void 0,
159
+ webUrl: w(r.webUrl),
126
160
  description: typeof r.description == "string" ? r.description : void 0
127
161
  };
128
162
  }
129
163
  return {
130
164
  version: a.version,
131
165
  defaultEnvironment: typeof a.defaultEnvironment == "string" && a.defaultEnvironment ? a.defaultEnvironment : void 0,
132
- environments: o
166
+ environments: s
133
167
  };
134
168
  }
135
- function E(n) {
136
- let r = w(n);
169
+ function N(n) {
170
+ let r = A(n);
137
171
  if (!e(r)) return null;
138
172
  let i = (e) => {
139
- throw new b("corrupt-local-state", `${y} (${r}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`, r);
173
+ throw new C("corrupt-local-state", `${b} (${r}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`, r);
140
174
  }, a;
141
175
  try {
142
176
  a = JSON.parse(t(r, "utf-8"));
143
177
  } catch (e) {
144
- return i(e.message);
178
+ return i(j(e));
145
179
  }
146
180
  if (!a || typeof a != "object" || Array.isArray(a)) return i("expected a JSON object");
147
181
  let o = a.selectedEnvironment;
148
182
  return o == null || o === "" ? null : typeof o == "string" ? o : i("\"selectedEnvironment\" must be a string");
149
183
  }
150
- function D(e, t) {
151
- let n = Object.keys(e.environments), r = n.join(", ") || "(none)", i = t.configPath ? `${v} (${t.configPath})` : v, a = (n, a, o) => {
152
- if (!e.environments[n]) throw new b("unknown-environment", `Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`, t.configPath);
184
+ function P(e, t) {
185
+ let n = Object.keys(e.environments), r = n.join(", ") || "(none)", i = t.configPath ? `${y} (${t.configPath})` : y, a = (n, a, o) => {
186
+ if (!e.environments[n]) throw new C("unknown-environment", `Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`, t.configPath);
153
187
  return {
154
188
  name: n,
155
189
  source: a
@@ -157,61 +191,60 @@ function D(e, t) {
157
191
  };
158
192
  if (t.explicitEnvName) return a(t.explicitEnvName, "explicit", "explicitly");
159
193
  if (t.envVarName) return a(t.envVarName, "env-var", "via PRIMITIVE_ENV");
160
- if (t.localSelection) return a(t.localSelection, "local", `in ${y}`);
194
+ if (t.localSelection) return a(t.localSelection, "local", `in ${b}`);
161
195
  if (e.defaultEnvironment) return a(e.defaultEnvironment, "default", "as \"defaultEnvironment\"");
162
196
  if (n.length === 1) return {
163
197
  name: n[0],
164
198
  source: "sole"
165
199
  };
166
- 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);
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);
167
201
  }
168
- function O(e = {}) {
169
- let t = e.env ?? process.env, n = e.configPath ?? S({
202
+ function F(e = {}) {
203
+ let t = e.env ?? process.env, n = e.configPath ?? O({
170
204
  cwd: e.cwd,
171
205
  env: t
172
206
  });
173
- if (!n) throw new b("missing-config", `No ${v} found in ${e.cwd ?? process.cwd()} or any parent directory. Run 'primitive init' to create one, or 'primitive env add <name>' to add an environment.`);
174
- let r = T(n), { name: i, source: a } = D(r, {
207
+ if (!n) throw new C("missing-config", S(e.cwd ?? process.cwd()));
208
+ let r = k(n), i = M(n), { name: a, source: o } = P(i, {
175
209
  explicitEnvName: e.explicitEnvName || null,
176
210
  envVarName: t.PRIMITIVE_ENV || null,
177
- localSelection: E(n),
211
+ localSelection: N(n),
178
212
  configPath: n
179
- }), o = r.environments[i];
180
- if (e.requireAppId && !o.appId) throw new b("missing-app-id", `Environment "${i}" in ${v} (${n}) has no "appId", which this build needs. Add one with 'primitive env add ${i} --api-url ${o.apiUrl} --app-id <id>' or edit the config.`, n);
213
+ }), s = i.environments[a];
181
214
  return {
182
- name: i,
183
- apiUrl: o.apiUrl,
184
- wsUrl: x(o.apiUrl),
185
- appId: o.appId,
186
- appName: o.appName,
187
- description: o.description,
188
- source: a,
215
+ name: a,
216
+ apiUrl: s.apiUrl,
217
+ wsUrl: D(s.apiUrl),
218
+ appId: s.appId,
219
+ appName: s.appName,
220
+ webUrl: s.webUrl,
221
+ description: s.description,
222
+ source: o,
189
223
  configPath: n,
190
- localStatePath: w(n),
191
- projectRoot: C(n)
224
+ localStatePath: A(n),
225
+ projectRoot: r
192
226
  };
193
227
  }
194
228
  //#endregion
195
229
  //#region src/dev-tools/vite-plugin/primitive-env.ts
196
- var k = [
230
+ var I = [
197
231
  "VITE_APP_ID",
198
232
  "VITE_API_URL",
199
233
  "VITE_WS_URL",
200
234
  "VITE_APP_NAME"
201
- ], A = "VITE_EXPECTED_PRIMITIVE_ENV", j = /* @__PURE__ */ new Map();
202
- function M(e, t) {
235
+ ], L = "VITE_EXPECTED_PRIMITIVE_ENV", R = /* @__PURE__ */ new Map();
236
+ function z(e, t) {
203
237
  let n = process.env[e];
204
- n !== void 0 && n !== "" && j.get(e) !== n || (process.env[e] = t, j.set(e, t));
238
+ n !== void 0 && n !== "" && R.get(e) !== n || (process.env[e] = t, R.set(e, t));
205
239
  }
206
- function N(e = {}) {
207
- return O({
240
+ function B(e = {}) {
241
+ return F({
208
242
  cwd: e.root,
209
243
  env: e.env,
210
- explicitEnvName: e.primitiveEnv ?? null,
211
- requireAppId: e.requireAppId
244
+ explicitEnvName: e.primitiveEnv ?? null
212
245
  });
213
246
  }
214
- function P(e, t, n) {
247
+ function V(e, t, n) {
215
248
  let r = (e) => n.includes(e) ? " (overridden)" : "", i = [
216
249
  `[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,
217
250
  `[primitive-env] apiUrl: ${t.apiUrl}${r("VITE_API_URL")}`,
@@ -222,12 +255,12 @@ function P(e, t, n) {
222
255
  ];
223
256
  return n.length > 0 && i.push(`[primitive-env] overridden by the environment: ${n.join(", ")}`), i.join("\n");
224
257
  }
225
- function F(e, t) {
258
+ function H(e, t) {
226
259
  let n = e?.envDir;
227
260
  return n === !1 ? null : typeof n == "string" && n !== "" ? c(t, n) : t;
228
261
  }
229
- function I(e, t) {
230
- let n = process.env[A];
262
+ function U(e, t) {
263
+ let n = process.env[L];
231
264
  if (n !== void 0 && n !== "") return {
232
265
  value: n,
233
266
  where: "the process environment"
@@ -239,7 +272,7 @@ function I(e, t) {
239
272
  ".env.local",
240
273
  ".env"
241
274
  ]) {
242
- let e = V(s(t, n))[A];
275
+ let e = J(s(t, n))[L];
243
276
  if (e !== void 0) return {
244
277
  value: e,
245
278
  where: n
@@ -247,48 +280,47 @@ function I(e, t) {
247
280
  }
248
281
  return null;
249
282
  }
250
- function L(e, t, n) {
283
+ function W(e, t, n) {
251
284
  return [
252
285
  `[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,
253
- `[primitive-env] expected: ${t.value} (${A} in ${t.where})`,
286
+ `[primitive-env] expected: ${t.value} (${L} in ${t.where})`,
254
287
  `[primitive-env] resolved: ${n.name} (selected: ${n.source})`,
255
288
  `[primitive-env] config: ${n.configPath}`,
256
289
  "",
257
- `Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${A} 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}.`,
258
291
  "",
259
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.`
260
293
  ].join("\n");
261
294
  }
262
- function R(e, t, n) {
263
- let r = I(e, t);
264
- if (r && r.value !== "" && r.value !== n.name) throw Error(L(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));
265
298
  }
266
- function z(e = {}) {
299
+ function K(e = {}) {
267
300
  let t = null, n = null, r, i = [], a = !1, o = null;
268
301
  return {
269
302
  name: "primitive-env",
270
303
  enforce: "pre",
271
304
  config(s, c) {
272
305
  a = c?.command === "serve", o = null;
273
- let l = s?.root ?? process.cwd(), u = c?.mode ?? "development", d = B(u, l), f = {};
274
- for (let e of k) {
275
- let t = process.env[e], n = t !== void 0 && j.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];
276
309
  n !== void 0 && n !== "" && (f[e] = n);
277
310
  }
278
311
  let p;
279
312
  try {
280
- p = O({
313
+ p = F({
281
314
  cwd: l,
282
- explicitEnvName: e.primitiveEnv ?? null,
283
- requireAppId: !f.VITE_APP_ID
315
+ explicitEnvName: e.primitiveEnv ?? null
284
316
  });
285
317
  } catch (e) {
286
- 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, {};
318
+ if (e instanceof C && 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, {};
287
319
  throw e;
288
320
  }
289
321
  if (!(f.VITE_APP_ID && f.VITE_API_URL)) {
290
- let e = F(s, l);
291
- R(u, e, p), o = {
322
+ let e = H(s, l);
323
+ G(u, e, p), o = {
292
324
  root: l,
293
325
  mode: u,
294
326
  dir: e
@@ -301,25 +333,25 @@ function z(e = {}) {
301
333
  VITE_WS_URL: p.wsUrl,
302
334
  VITE_APP_NAME: p.appName
303
335
  }, h = { "import.meta.env.VITE_PRIMITIVE_ENV": JSON.stringify(p.name) }, g = [];
304
- for (let e of k) {
336
+ for (let e of I) {
305
337
  if (f[e] !== void 0) {
306
338
  g.push(e);
307
339
  continue;
308
340
  }
309
341
  let t = m[e];
310
- t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t), M(e, t));
342
+ t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t), z(e, t));
311
343
  }
312
- return M("VITE_PRIMITIVE_ENV", p.name), i = g, n = {
344
+ return z("VITE_PRIMITIVE_ENV", p.name), i = g, n = {
313
345
  apiUrl: f.VITE_API_URL ?? p.apiUrl,
314
346
  wsUrl: f.VITE_WS_URL ?? p.wsUrl,
315
347
  appId: f.VITE_APP_ID ?? p.appId,
316
348
  appName: r
317
- }, e.logResolved !== !1 && console.log(P(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 };
318
350
  },
319
351
  configResolved(e) {
320
352
  if (!o || !t) return;
321
- let n = F(e, o.root), r = e?.mode ?? o.mode;
322
- n === o.dir && r === o.mode || (R(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 = {
323
355
  root: o.root,
324
356
  mode: r,
325
357
  dir: n
@@ -342,17 +374,17 @@ function z(e = {}) {
342
374
  }
343
375
  };
344
376
  }
345
- function B(e, t) {
377
+ function q(e, t) {
346
378
  let n = [
347
379
  ".env",
348
380
  ".env.local",
349
381
  `.env.${e}`,
350
382
  `.env.${e}.local`
351
383
  ], r = {};
352
- for (let e of n) Object.assign(r, V(s(t, e)));
384
+ for (let e of n) Object.assign(r, J(s(t, e)));
353
385
  return r;
354
386
  }
355
- function V(n) {
387
+ function J(n) {
356
388
  if (!e(n)) return {};
357
389
  let r = {};
358
390
  for (let e of t(n, "utf-8").split(/\r?\n/)) {
@@ -366,4 +398,4 @@ function V(n) {
366
398
  return r;
367
399
  }
368
400
  //#endregion
369
- export { b as PrimitiveEnvError, m as primitiveDevTools, z as primitiveEnv, N as resolvePrimitiveEnv };
401
+ export { C as PrimitiveEnvError, m as primitiveDevTools, K as primitiveEnv, B as resolvePrimitiveEnv };
@@ -2,7 +2,7 @@
2
2
  * `primitiveEnv()` — Primitive environment configuration for a Vite app (#2873).
3
3
  *
4
4
  * A scaffolded app used to type its backend URL and app ID twice: once in
5
- * `.primitive/config.json` (which every `primitive` command reads) and again in
5
+ * `primitive/config.json` (which every `primitive` command reads) and again in
6
6
  * `.env` / `.env.production`. This plugin removes the second copy. It resolves
7
7
  * the selected Primitive environment at config time and `define`s the keys the
8
8
  * app already reads:
@@ -45,8 +45,6 @@ export interface ResolvePrimitiveEnvOptions {
45
45
  env?: Record<string, string | undefined>;
46
46
  /** An explicit environment name (e.g. from `--primitive-env`). */
47
47
  primitiveEnv?: string | null;
48
- /** Fail when the resolved environment has no `appId`. */
49
- requireAppId?: boolean;
50
48
  }
51
49
  /**
52
50
  * Resolves the Primitive environment for a project. A thin wrapper over the