@quatronic/qore 0.1.5 → 0.1.7

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
@@ -23,6 +23,11 @@ qore version # CLI + portal version info
23
23
 
24
24
  qore env pull # write this module's local secrets into an env file
25
25
  qore run -- <command> # run a command with those secrets in its environment
26
+
27
+ qore errors --env stag # recent unresolved errors
28
+ qore errors FRONTEND-1A --env prod --with trace,logs # one error, its trace and logs
29
+ qore traces --env stag --slower-than 1s # slow requests
30
+ qore logs --env stag --level error # error logs
26
31
  ```
27
32
 
28
33
  ### Portals
@@ -46,7 +51,32 @@ the portal. Working from a personal fork whose `origin` the portal doesn't
46
51
  know? As long as an `upstream` remote points at the real repository, that one
47
52
  resolves — the context line then says `(upstream)`.
48
53
 
49
- Pass `--module <slug|id>` to pick a module explicitly; the flag always wins
54
+ Outside a repository, with a projects folder set (see `qore init`), the
55
+ order is: the project you are standing in; else `[project]` /
56
+ `--project <ref>` (`app`, `app/module`, `tenant/app` or `tenant/app/module`,
57
+ matched against your local checkouts); else an interactive pick. `qore dev`
58
+ takes the reference as an argument (`qore dev <app>`); `qore dev`, `qore env
59
+ pull`, `qore run` and `qore status` take `--project`. `qore run --project`
60
+ only chooses which module's secrets are used; the command still runs in the
61
+ current directory. `qore env pull --project` writes into the located module,
62
+ and a relative `--target` then resolves against that project directory, not
63
+ the directory you ran it from.
64
+
65
+ A repository that is no module counts as outside one: standing in some other
66
+ codebase, `qore dev` asks the portal about its remotes and, when they match no
67
+ module (or it has no remote Qore can match), offers your projects just the
68
+ same. A repository inside a known project is never asked about, and a portal
69
+ that cannot answer keeps today's error.
70
+
71
+ Logged out with a projects folder set, the local lookup still runs first: a
72
+ folder that holds no projects gives `QORE_PROJECT_NOT_FOUND`; otherwise the
73
+ project is located exactly as when logged in (a match, a picker, or
74
+ `QORE_CONTEXT_REQUIRED` without a terminal), and the login error comes from
75
+ the portal lookup that follows. Only without a projects folder does a logged-out
76
+ command outside a project go straight to the login error.
77
+
78
+ Pass `--module <slug|id>` to pick a module explicitly (it keeps its meaning and,
79
+ like `--app`, still uses the portal lookup when you are not in a project); the flag always wins
50
80
  over the git remote. Inside a repository, `qore` still looks up the remote's
51
81
  own module (from the cache, or with one extra request) only so the context
52
82
  line can tell you when the flag overrides it. If a module is linked to more
@@ -92,7 +122,9 @@ qore env pull
92
122
 
93
123
  - The target file defaults to the module type's own convention (e.g.
94
124
  `.env.local`), or `.qore.json`'s `envFile`, or `--target <path>` — always
95
- resolved against, and required to stay inside, the repository.
125
+ required to stay inside the repository. `envFile` resolves against the
126
+ repository root; `--target` against the current directory, or with
127
+ `--project` against the located project directory.
96
128
  - If the file doesn't exist yet, it's seeded from `.env.example` when one is
97
129
  present.
98
130
  - Existing values you've hand-edited are kept by default. A key the portal
@@ -301,6 +333,39 @@ If a repository resolves to no module on any portal you're logged in to,
301
333
  the error lists the portals it tried and, when a staging repository looks
302
334
  likely, suggests `qore login --portal staging`.
303
335
 
336
+ ### Projects folder & `qore init`
337
+
338
+ `qore init` is the guided setup. It runs four steps and reports each as
339
+ `done`, `already` or `skipped`, so running it again is safe:
340
+
341
+ 1. **Projects folder**: where your apps live (default `~/qore`; `--root <path>`
342
+ sets it without asking). Nothing existing is moved.
343
+ 2. **Login**: skipped when you are already logged in, and with `--no-input`.
344
+ 3. **Tenant**: `already` when a tenant is active (`done` right after the login
345
+ step logged you in). Otherwise skipped with
346
+ `--no-input` or when you are not logged in (run `qore tenant use <slug>`
347
+ later), skipped with no tenants, selected without a prompt when you have
348
+ one, a picker when you have several.
349
+ 4. **First app**: `--clone <app>` (with `--tenant <slug>` to disambiguate)
350
+ clones it; interactively it asks.
351
+
352
+ With `--json`, stdout is one document: `{"projectsRoot": "<path>|null",
353
+ "steps": {"root"|"login"|"tenant"|"clone": {"status", "detail?"}}}`.
354
+
355
+ Apps clone into `<root>/<tenant>/<app>/<module>`. A checkout outside the
356
+ folder registers itself the first time you use it (`qore clone <app> <dir>`,
357
+ `qore dev`, ...); a registered checkout that was deleted is dropped. With a
358
+ projects folder set, `qore dev`, `qore env pull`, `qore run` and `qore status`
359
+ work from any directory (see Repository context).
360
+
361
+ ```sh
362
+ qore config root # show the folder and how many projects it holds
363
+ qore config root <path> # set it
364
+ qore config root --unset # clear it; known projects stay findable
365
+ ```
366
+
367
+ `qore doctor` checks that the folder exists and is writable.
368
+
304
369
  ### Workspaces
305
370
 
306
371
  `qore clone` sets up a local directory holding one or more of an app's
@@ -319,6 +384,9 @@ qore sync # clone any module that's new, fetch the rest
319
384
  qore sync --pull # ...and fast-forward every clean repository with an upstream
320
385
  ```
321
386
 
387
+ - **Where it clones.** Without `[dir]` and with a projects folder set, `qore
388
+ clone` uses `<root>/<tenant>/<app>`. Without a projects folder it behaves as
389
+ described above and prints a tip to run `qore init`.
322
390
  - **`--protocol https|ssh`** picks the clone URL (default `https`). `ssh`
323
391
  rewrites `https://github.com/o/r` to `git@github.com:o/r.git`; your own
324
392
  git `insteadOf` config still applies on top of either.
@@ -485,8 +553,8 @@ qore whoami --json
485
553
  | Code | Meaning |
486
554
  |------|---------|
487
555
  | 0 | Success |
488
- | 1 | Internal error, `git` is not installed or not on `PATH`, the OS keychain is unavailable/access was denied, or qore itself needs a newer Node (`QORE_NODE_VERSION`, checked by `qore doctor`'s own `node` check against qore's own `process.version`); `qore dev`: its package manager isn't installed (`QORE_PACKAGE_MANAGER`), its install failed (`QORE_INSTALL_FAILED`), Docker is missing (`QORE_DOCKER_MISSING`), not running (`QORE_DOCKER_NOT_RUNNING`) or its compose v2 plugin is missing (`QORE_DOCKER_COMPOSE_MISSING`), a `db:up`/service failed, never became healthy (`QORE_SERVICE_UNHEALTHY`) or its data is incompatible (`QORE_SERVICE_DATA_INCOMPATIBLE`), or the repository's own `engines.node` doesn't match the `node` on `PATH` (`QORE_NODE_VERSION`, a different check from qore's own — `qore doctor`'s `node:<module>` check, run only in a trusted repository) |
489
- | 2 | Missing or invalid context (e.g. a bad `--portal` value, or no module selected), or the module is part of several apps and no `--app` was given; `qore dev`: a port is already in use (`QORE_PORT_IN_USE`) or the repository's dev setup isn't supported (`QORE_DEV_UNSUPPORTED`) |
556
+ | 1 | Internal error, `git` is not installed or not on `PATH`, the OS keychain is unavailable/access was denied, or qore itself needs a newer Node (`QORE_NODE_VERSION`, checked by `qore doctor`'s own `node` check against qore's own `process.version`); `qore dev`: its package manager isn't installed (`QORE_PACKAGE_MANAGER`), its install failed (`QORE_INSTALL_FAILED`), Docker is missing (`QORE_DOCKER_MISSING`), not running (`QORE_DOCKER_NOT_RUNNING`) or its compose v2 plugin is missing (`QORE_DOCKER_COMPOSE_MISSING`), a `db:up`/service failed, never became healthy (`QORE_SERVICE_UNHEALTHY`) or its data is incompatible (`QORE_SERVICE_DATA_INCOMPATIBLE`), or the repository's own `engines.node` doesn't match the `node` on `PATH` (`QORE_NODE_VERSION`, a different check from qore's own — `qore doctor`'s `node:<module>` check, run only in a trusted repository); or the projects folder isn't writable (`QORE_ROOT_NOT_WRITABLE`, fix its permissions or choose another folder) |
557
+ | 2 | Missing or invalid context (e.g. a bad `--portal` value, or no module selected), or the module is part of several apps and no `--app` was given; `qore dev`: a port is already in use (`QORE_PORT_IN_USE`) or the repository's dev setup isn't supported (`QORE_DEV_UNSUPPORTED`); projects folder: not set and not inside a project, for a logged-in user (`QORE_ROOT_NOT_SET`, run `qore init`; logged out with no folder you get the login error, exit 4, and logged out with a folder the local lookup runs first, so an empty folder still gives `QORE_PROJECT_NOT_FOUND`), not usable as a folder (`QORE_ROOT_INVALID`, pick another with `qore init --root <path>`), or no local project matches the reference or the folder holds none (`QORE_PROJECT_NOT_FOUND`, run `qore clone <app>`) |
490
558
  | 4 | Not logged in, session/login expired, login denied, or clock skew |
491
559
  | 5 | Access denied — lost tenant access, resource not found, no developer access |
492
560
  | 6 | Auth or API temporarily unreachable/unavailable |
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a8210538-dc3e-507d-ab33-bdf6a49d6d16")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="885f6de1-0da7-54a5-86df-beaf550bdd8a")}catch(e){}}();
4
4
  import { createRequire as __qoreCreateRequire } from "node:module"; const require = __qoreCreateRequire(import.meta.url);
5
5
 
6
6
  // src/core/telemetry/scrub.ts
@@ -52,6 +52,21 @@ function replaceHome(s, ctx) {
52
52
  }
53
53
  return out;
54
54
  }
55
+ var PKG = "node_modules/@quatronic/qore/";
56
+ var NM = "node_modules/";
57
+ function rewritePath(p, ctx) {
58
+ if (p.startsWith("app://") || !/^(?:file:\/\/|\/|[A-Za-z]:[\\/])/.test(p)) return { path: p };
59
+ let s = p.replace(/^file:\/\//, "");
60
+ if (ctx.platform === "win32") s = s.replace(/\\/g, "/").replace(/^\/(?=[A-Za-z]:)/, "");
61
+ const pkg = s.lastIndexOf(PKG);
62
+ const nm = s.lastIndexOf(NM);
63
+ if (pkg >= 0 && pkg === nm) return { path: `app:///${s.slice(pkg + PKG.length)}`, inApp: true };
64
+ if (nm >= 0) return { path: `app:///${s.slice(nm)}`, inApp: false };
65
+ return { path: `app:///${replaceHome(s, ctx).replace(/^\/+/, "")}` };
66
+ }
67
+ function framePath(p, ctx) {
68
+ return rewritePath(p, ctx).path;
69
+ }
55
70
  function scrubText(s, ctx) {
56
71
  let out = s;
57
72
  for (const v of ctx.secretEnvValues) out = replaceLiteral(out, v, "[env]", "g");
@@ -83,8 +98,8 @@ function scrubBreadcrumb(b, ctx) {
83
98
  return { ...b, message: b.message === void 0 ? void 0 : scrubText(b.message, ctx), data: void 0 };
84
99
  }
85
100
  function scrubEvent(e, ctx) {
101
+ e.user = { ip_address: null };
86
102
  delete e.server_name;
87
- delete e.user;
88
103
  delete e.request;
89
104
  delete e.extra;
90
105
  delete e.modules;
@@ -97,8 +112,12 @@ function scrubEvent(e, ctx) {
97
112
  for (const v of e.exception?.values ?? []) {
98
113
  if (v.value !== void 0) v.value = scrubText(v.value, ctx);
99
114
  for (const f of v.stacktrace?.frames ?? []) {
100
- if (f.filename) f.filename = replaceHome(f.filename, ctx);
101
- if (f.abs_path) f.abs_path = replaceHome(f.abs_path, ctx);
115
+ for (const k of ["filename", "abs_path"]) {
116
+ if (!f[k]) continue;
117
+ const r = rewritePath(f[k], ctx);
118
+ f[k] = r.path;
119
+ if (r.inApp !== void 0) f.in_app = r.inApp;
120
+ }
102
121
  if (f.module) f.module = replaceHome(f.module, ctx);
103
122
  delete f.vars;
104
123
  delete f.pre_context;
@@ -106,7 +125,7 @@ function scrubEvent(e, ctx) {
106
125
  delete f.post_context;
107
126
  }
108
127
  }
109
- for (const img of e.debug_meta?.images ?? []) if (img.code_file) img.code_file = replaceHome(img.code_file, ctx);
128
+ for (const img of e.debug_meta?.images ?? []) if (img.code_file) img.code_file = framePath(img.code_file, ctx);
110
129
  if (e.breadcrumbs) e.breadcrumbs = e.breadcrumbs.map((b) => scrubBreadcrumb(b, ctx)).filter((b) => b !== null);
111
130
  return e;
112
131
  }
@@ -117,5 +136,5 @@ export {
117
136
  scrubBreadcrumb,
118
137
  scrubEvent
119
138
  };
120
- //# sourceMappingURL=chunk-QYBDINUC.js.map
121
- //# debugId=a8210538-dc3e-507d-ab33-bdf6a49d6d16
139
+ //# sourceMappingURL=chunk-OAU6HJHZ.js.map
140
+ //# debugId=885f6de1-0da7-54a5-86df-beaf550bdd8a