@auersperg/flare 0.3.2 → 0.3.5

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.
Files changed (45) hide show
  1. package/README.md +10 -4
  2. package/dist/cli/{chunk-x14smx1y.js → chunk-5s6zv1h9.js} +1 -1
  3. package/dist/cli/{chunk-5cq8wgte.js → chunk-5yg1zj5n.js} +48 -29
  4. package/dist/cli/{chunk-786w6vrj.js → chunk-fv98dfg5.js} +21 -1
  5. package/dist/cli/chunk-r3ceakrn.js +1366 -0
  6. package/dist/cli/flare.js +122 -4
  7. package/dist/platform/admin.js +790 -0
  8. package/dist/platform/dashboard/_astro/auth-view.UTGGCEHc.js +1 -0
  9. package/dist/platform/dashboard/_astro/cli-approval.BZAWmpiR.js +1 -0
  10. package/dist/platform/dashboard/_astro/client.BUUZgEFj.js +1 -0
  11. package/dist/platform/dashboard/_astro/client.Bcl1NrNO.js +1 -0
  12. package/dist/platform/dashboard/_astro/client.BeKNsjPN.js +9 -0
  13. package/dist/platform/dashboard/_astro/common.DPoFQu44.js +1 -0
  14. package/dist/platform/dashboard/_astro/data-view.BgYyTCMN.js +1 -0
  15. package/dist/platform/dashboard/_astro/functions-view.PUkng3T1.js +1 -0
  16. package/dist/platform/dashboard/_astro/geist-cyrillic-ext-wght-normal.DjL33-gN.woff2 +0 -0
  17. package/dist/platform/dashboard/_astro/geist-cyrillic-wght-normal.BEAKL7Jp.woff2 +0 -0
  18. package/dist/platform/dashboard/_astro/geist-latin-ext-wght-normal.DC-KSUi6.woff2 +0 -0
  19. package/dist/platform/dashboard/_astro/geist-latin-wght-normal.BgDaEnEv.woff2 +0 -0
  20. package/dist/platform/dashboard/_astro/geist-vietnamese-wght-normal.6IgcOCM7.woff2 +0 -0
  21. package/dist/platform/dashboard/_astro/index.astro_astro_type_script_index_0_lang.BEuO3H0E.js +4 -0
  22. package/dist/platform/dashboard/_astro/index.lobU7uK5.css +2 -0
  23. package/dist/platform/dashboard/_astro/input-group.CJxPRHej.js +1 -0
  24. package/dist/platform/dashboard/_astro/sdk-view.COmbEZrF.js +1 -0
  25. package/dist/platform/dashboard/_astro/services-view.C34dy0dk.js +1 -0
  26. package/dist/platform/dashboard/_astro/settings-view.IuD2r5JW.js +3 -0
  27. package/dist/platform/dashboard/_headers +3 -0
  28. package/dist/platform/dashboard/bootstrap/action.js +263 -0
  29. package/dist/platform/dashboard/bootstrap/api.ts +5 -0
  30. package/dist/platform/dashboard/bootstrap/facet.js +914 -0
  31. package/dist/platform/dashboard/bootstrap/manifest.json +5 -0
  32. package/dist/platform/dashboard/bootstrap/openapi.json +18 -0
  33. package/dist/platform/dashboard/bootstrap/release.json +11 -0
  34. package/dist/platform/dashboard/bootstrap/schema.json +1 -0
  35. package/dist/platform/dashboard/index.html +1 -0
  36. package/dist/platform/manifest.json +195 -0
  37. package/dist/platform/migrations/0001.sql +8 -0
  38. package/dist/platform/migrations/0002_project_aliases.sql +6 -0
  39. package/dist/platform/migrations/0003_cli_login.sql +9 -0
  40. package/dist/platform/migrations/0004_retention.sql +4 -0
  41. package/dist/platform/migrations/0005_project_deletion.sql +11 -0
  42. package/dist/platform/migrations/0006_platform_installation.sql +8 -0
  43. package/dist/platform/runtime.js +9392 -0
  44. package/dist/sdk/client.js +10 -2
  45. package/package.json +1 -1
package/README.md CHANGED
@@ -63,7 +63,7 @@ flare deploy --env dev --release release
63
63
 
64
64
  Immutable output contains facet/action modules, `schema.json`, manifest, checksums, generated TypeScript API and OpenAPI 3.1. Only ABI 4 is accepted. No old `tables` declarations, `--migrations` flag or Drizzle pipeline.
65
65
 
66
- Browser approval is protected by online Access/owner authorization and same-origin CSRF. Project-scoped credentials stay outside source/frontend env. Dev publishes to an already provisioned platform; general `platform init` is not implemented. No npm publication or cloud provisioning occurs during local verification.
66
+ Browser approval is protected by online Access/owner authorization and same-origin CSRF. Project-scoped credentials stay outside source/frontend env. Dev publishes to an already provisioned platform. Source 0.3.5 includes `platform install|status|update|adopt` plus a checksummed Core/dashboard payload, with separate Cloudflare account authorization; see [platform lifecycle](../../docs/platform-lifecycle.md). Disposable install/recovery and genuine 0.3.3 → 0.3.4 / 0.3.4 → 0.3.5 upgrades passed in the owner’s Cloudflare account. The existing personal panel also passed explicit external compiled-CLI adoption, preserving data/auth/files and namespace identities. This remains a trusted-team preview; independent-account acceptance with a full-scope platform CLI token is not yet complete. Check the registry for exact-version availability rather than assuming a moving tag contains the platform commands. No npm publication or cloud provisioning occurs during local verification.
67
67
 
68
68
  ## Immutable releases
69
69
 
@@ -80,6 +80,8 @@ Promote copies the selected immutable dev bundle to prod without recompiling or
80
80
 
81
81
  `--cmd` generates client references for the exact selected bundle and builds the frontend **before** activating the backend. The child receives the selected environment URL via `FLARE_URL`, `PUBLIC_FLARE_URL`, `VITE_FLARE_URL`, `NEXT_PUBLIC_FLARE_URL` and `EXPO_PUBLIC_FLARE_URL`; local dev env files remain unchanged. A failed build does not publish backend code. Framework build variables must be public URLs, not credentials.
82
82
 
83
+ Every CLI deploy compares the expected active backend hash, including without `--cmd`; conflicts are not retried. A failed frontend build restores the previous generated `api.ts`/`references.ts` (or their absence). Invalid/unconfirmed deployments do not scaffold or evaluate app code. Management errors retain HTTP status; interrupted writes and malformed successful responses are reported as unknown outcomes, never replayed automatically.
84
+
83
85
  Frontend hosting stays with native Wrangler or another hosting tool. An application release script can sequence Flare + build + Wrangler. Frontend publication failure after backend activation is an explicit partial release, not an atomic transaction. Dashboard Health → Development/Production releases offers contract inspection, backend promotion and rollback on demand, with no polling. It does not publish the frontend.
84
86
 
85
87
  Isolated historical preview environments and a paired frontend/backend version catalogue are not implemented. A saved backend hash is not a preview URL or a Git commit. Use additive contracts when old clients may remain active.
@@ -108,14 +110,18 @@ const url = import.meta.env.PUBLIC_FLARE_URL;
108
110
  const auth = createPasswordAuth({ url });
109
111
  const client = createClient({ url, getToken: auth.getToken });
110
112
  const stopAuth = auth.onChange(() => client.refreshAuth());
111
- await auth.register("my-login", "a long unique passphrase");
112
- // Later: await auth.login(login, password), auth.me(), auth.changePassword(old, next).
113
+ await auth.restore(); // Verify a saved session before rendering protected UI.
114
+ // Explicit sign-in: auth.register(login, password) or auth.login(login, password).
115
+ // Account operations: auth.me(), auth.changePassword(old, next).
113
116
  await auth.logout();
114
117
  stopAuth();
115
118
  client.dispose();
119
+ auth.dispose();
116
120
  ```
117
121
 
118
- Sessions are memory-only and expire after at most 12 hours. Reload requires login again. Password reset/block/revoke in Auth disconnects affected live users. Owner/Access manages accounts; application users and project CLI credentials do not gain dashboard privileges. Public login/registration have bounded rate limits; public registration is not equivalent to public access to private rows. Passwords require 6–128 characters. There is no email verification/recovery or MFA in this minimal version; owner reset is available. Existing short-lived R2 download grants remain valid for their explicit TTL, not until session logout.
122
+ Sessions expire after at most 12 hours. Browsers default to localStorage scoped to the deployment URL; `restore()` verifies the saved session against the server. Server/mobile callers provide storage explicitly or use `storage: null` for memory-only auth. Temporary network failures do not erase saved credentials; cross-tab logout is synchronized. `dispose()` is not logout. This is bearer-token storage, not HttpOnly-cookie authentication: prevent XSS in the application. No perpetual refresh is implemented.
123
+
124
+ Password reset/block/revoke disconnects affected live users. Live cache is cleared when authorization is rejected, including during reconnect ticket acquisition; a transient connection failure keeps the last valid snapshot. Owner/Access manages accounts; application users and project CLI credentials do not gain account-management privileges. Handlers enforce record ownership. Passwords require 6–128 characters; registration is rate-limited and closed by default. Email verification/recovery and MFA are not implemented. Existing R2 download grants remain valid for their explicit TTL, not until session logout.
119
125
 
120
126
  ## License and distribution
121
127
 
@@ -102,7 +102,7 @@ ${url}`);
102
102
  await writeFile(join(directory, key + ".json"), JSON.stringify({ token, expiresAt: result.expiresAt }) + `
103
103
  `, { mode: 384 });
104
104
  process.env.FLARE_DEPLOY_TOKEN = token;
105
- const { link } = await import("./chunk-5cq8wgte.js");
105
+ const { link } = await import("./chunk-5yg1zj5n.js");
106
106
  return link({ platform, project: result.project });
107
107
  }
108
108
  throw Error("Login expired. Run flare dev again.");
@@ -26,26 +26,46 @@ async function request(platform, path, body) {
26
26
  return "null";
27
27
  }));
28
28
  if (config) {
29
- const { storedToken } = await import("./chunk-x14smx1y.js");
29
+ const { storedToken } = await import("./chunk-5s6zv1h9.js");
30
30
  token = await storedToken(platform, config.project);
31
31
  }
32
32
  }
33
33
  if (!token)
34
34
  throw Error("Sign in with flare dev; CI can set FLARE_DEPLOY_TOKEN");
35
- const r = await fetch(allowedUrl(platform) + path, {
36
- method: body === undefined ? "GET" : "POST",
37
- headers: {
38
- authorization: `Bearer ${token}`,
39
- ...body === undefined ? {} : { "content-type": "application/json" }
40
- },
41
- body: body === undefined ? undefined : JSON.stringify(body),
42
- redirect: "error",
43
- signal: AbortSignal.timeout(60000)
44
- });
45
- const result = await r.json();
35
+ const url = allowedUrl(platform) + path;
36
+ const write = body !== undefined;
37
+ const encoded = write ? JSON.stringify(body) : undefined;
38
+ let r;
39
+ try {
40
+ r = await fetch(url, {
41
+ method: write ? "POST" : "GET",
42
+ headers: {
43
+ authorization: `Bearer ${token}`,
44
+ ...write ? { "content-type": "application/json" } : {}
45
+ },
46
+ body: encoded,
47
+ redirect: "error",
48
+ signal: AbortSignal.timeout(60000)
49
+ });
50
+ } catch {
51
+ const error = Error(write ? "Management write outcome is unknown; inspect current state before retrying. Writes are not automatically retried." : "Management request interrupted or timed out");
52
+ error.ambiguous = write;
53
+ throw error;
54
+ }
55
+ let result;
56
+ try {
57
+ result = await r.json();
58
+ } catch {
59
+ const error = Error(`Invalid management response (HTTP ${r.status}); ${write && (r.ok || r.status >= 500) ? "write outcome is unknown; inspect current state before retrying" : "check platform availability and authorization"}`);
60
+ error.status = r.status;
61
+ error.ambiguous = write && (r.ok || r.status >= 500);
62
+ throw error;
63
+ }
46
64
  if (!r.ok) {
47
- const error = Error(`${result.error ?? "Deployment failed"} (HTTP ${r.status}); writes are not automatically retried`);
65
+ const code = typeof result?.error === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(result.error) ? result.error : "Management request failed";
66
+ const error = Error(`${code} (HTTP ${r.status}); writes are not automatically retried`);
48
67
  error.status = r.status;
68
+ error.ambiguous = write && r.status >= 500;
49
69
  throw error;
50
70
  }
51
71
  return result;
@@ -68,9 +88,6 @@ async function link(options) {
68
88
  async function deploy(options = {}) {
69
89
  if (!options.release) {
70
90
  const config = JSON.parse(await readFile(".flare/project.json", "utf8"));
71
- const { prepare, generateApi } = await import("./chunk-786w6vrj.js");
72
- const { buildApplication } = await import("./chunk-vx7kmczm.js");
73
- const source = await prepare(), directory = resolve(".flare/releases/" + randomUUID());
74
91
  const env = options.env ?? "prod";
75
92
  if (!["dev", "prod"].includes(env))
76
93
  throw Error("Environment must be dev or prod");
@@ -89,6 +106,9 @@ async function deploy(options = {}) {
89
106
  prompt.close();
90
107
  }
91
108
  }
109
+ const { prepare, generateApi } = await import("./chunk-fv98dfg5.js");
110
+ const { buildApplication } = await import("./chunk-vx7kmczm.js");
111
+ const source = await prepare(), directory = resolve(".flare/releases/" + randomUUID());
92
112
  try {
93
113
  await buildApplication({ ...source, outdir: directory });
94
114
  const result = await deploy({
@@ -118,13 +138,13 @@ async function deploy(options = {}) {
118
138
  facet: await read("facet.js"),
119
139
  action: await read("action.js")
120
140
  };
121
- let expected;
141
+ const health = await request(config.platform, `/api/projects/${config.project}/${env}/health`);
142
+ const expected = health?.active;
143
+ if (!/^[a-f0-9]{64}$/.test(expected ?? ""))
144
+ throw Error("Environment has no active backend; inspect dashboard Health before deploying");
122
145
  if (options.cmd) {
123
- const health = await request(config.platform, `/api/projects/${config.project}/${env}/health`);
124
- expected = health.active;
125
- const { generateApi } = await import("./chunk-786w6vrj.js");
126
- await generateApi(directory);
127
- await frontendBuild(config, env, options.cmd);
146
+ const { withGeneratedApi } = await import("./chunk-fv98dfg5.js");
147
+ await withGeneratedApi(directory, () => frontendBuild(config, env, options.cmd));
128
148
  }
129
149
  return request(config.platform, `/api/projects/${config.project}/${env}/deploy`, { bundle, confirm: options.confirm, expected });
130
150
  }
@@ -133,14 +153,14 @@ async function dev(options = {}) {
133
153
  throw Error("Watch publishes only to dev; use deploy for production");
134
154
  const simple = !options.entry;
135
155
  if (simple) {
136
- const { scaffold } = await import("./chunk-786w6vrj.js");
156
+ const { scaffold } = await import("./chunk-fv98dfg5.js");
137
157
  await scaffold();
138
158
  try {
139
159
  await access(".flare/project.json");
140
160
  } catch (e) {
141
161
  if (e.code !== "ENOENT")
142
162
  throw e;
143
- const { connect } = await import("./chunk-x14smx1y.js");
163
+ const { connect } = await import("./chunk-5s6zv1h9.js");
144
164
  await connect();
145
165
  }
146
166
  }
@@ -152,7 +172,7 @@ async function dev(options = {}) {
152
172
  } catch (e) {
153
173
  if (process.env.FLARE_DEPLOY_TOKEN || e.status !== 401 && !e.message.startsWith("Sign in"))
154
174
  throw e;
155
- const { connect } = await import("./chunk-x14smx1y.js");
175
+ const { connect } = await import("./chunk-5s6zv1h9.js");
156
176
  await connect();
157
177
  }
158
178
  }
@@ -167,7 +187,7 @@ async function dev(options = {}) {
167
187
  try {
168
188
  const outdir = resolve(".flare/releases/" + randomUUID());
169
189
  try {
170
- const { prepare, generateApi, frontendEnvironment } = await import("./chunk-786w6vrj.js");
190
+ const { prepare, generateApi, frontendEnvironment } = await import("./chunk-fv98dfg5.js");
171
191
  const source = simple ? await prepare() : { entry: options.entry };
172
192
  const release = await buildApplication({ ...source, outdir });
173
193
  if (release.hash !== hash) {
@@ -289,14 +309,13 @@ async function releaseOperation(options, operation) {
289
309
  if (bundle.release.hash !== options.hash)
290
310
  throw Error("Release hash mismatch");
291
311
  const { generateReferences } = await import("./chunk-vx7kmczm.js");
292
- const { generateApi } = await import("./chunk-786w6vrj.js");
312
+ const { withGeneratedApi } = await import("./chunk-fv98dfg5.js");
293
313
  await mkdir(".flare", { recursive: true });
294
314
  const directory = await mkdtemp(resolve(".flare/release-contract-"));
295
315
  try {
296
316
  await writeFile(join(directory, "api.ts"), await generateReferences(bundle.manifest));
297
317
  await writeFile(join(directory, "manifest.json"), JSON.stringify(bundle.manifest));
298
- await generateApi(directory);
299
- await frontendBuild(config, env, options.cmd);
318
+ await withGeneratedApi(directory, () => frontendBuild(config, env, options.cmd));
300
319
  } finally {
301
320
  await rm(directory, { recursive: true, force: true });
302
321
  }
@@ -140,6 +140,25 @@ async function generateApi(directory) {
140
140
  export const api = ${serialize(tree)} as const;
141
141
  `);
142
142
  }
143
+ async function withGeneratedApi(directory, build) {
144
+ const files = ["flare/_generated/api.ts", "flare/_generated/references.ts"];
145
+ const previous = await Promise.all(files.map((file) => readFile(file).catch((error) => {
146
+ if (error.code !== "ENOENT")
147
+ throw error;
148
+ return null;
149
+ })));
150
+ try {
151
+ await generateApi(directory);
152
+ return await build();
153
+ } catch (error) {
154
+ try {
155
+ await Promise.all(files.map((file, i) => previous[i] === null ? rm(file, { force: true }) : writeFile(file, previous[i])));
156
+ } catch (restoreError) {
157
+ throw new AggregateError([error, restoreError], "Build failed and local client references could not be restored");
158
+ }
159
+ throw error;
160
+ }
161
+ }
143
162
  async function frontendEnvironment(url) {
144
163
  const pkg = JSON.parse(await readFile("package.json", "utf8"));
145
164
  const dependencies = { ...pkg.dependencies, ...pkg.devDependencies };
@@ -165,5 +184,6 @@ export {
165
184
  frontendEnvironment,
166
185
  generateApi,
167
186
  prepare,
168
- scaffold
187
+ scaffold,
188
+ withGeneratedApi
169
189
  };