@objectstack/runtime 6.7.1 → 6.8.1

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/dist/index.d.cts CHANGED
@@ -98,6 +98,7 @@ declare const StandaloneStackConfigSchema: z.ZodObject<{
98
98
  }>>;
99
99
  environmentId: z.ZodOptional<z.ZodString>;
100
100
  artifactPath: z.ZodOptional<z.ZodString>;
101
+ projectRoot: z.ZodOptional<z.ZodString>;
101
102
  }, z.core.$strip>;
102
103
  type StandaloneStackConfig = z.input<typeof StandaloneStackConfigSchema>;
103
104
  interface StandaloneStackResult {
package/dist/index.d.ts CHANGED
@@ -98,6 +98,7 @@ declare const StandaloneStackConfigSchema: z.ZodObject<{
98
98
  }>>;
99
99
  environmentId: z.ZodOptional<z.ZodString>;
100
100
  artifactPath: z.ZodOptional<z.ZodString>;
101
+ projectRoot: z.ZodOptional<z.ZodString>;
101
102
  }, z.core.$strip>;
102
103
  type StandaloneStackConfig = z.input<typeof StandaloneStackConfigSchema>;
103
104
  interface StandaloneStackResult {
package/dist/index.js CHANGED
@@ -2122,7 +2122,19 @@ var StandaloneStackConfigSchema = z.object({
2122
2122
  databaseAuthToken: z.string().optional(),
2123
2123
  databaseDriver: z.enum(["sqlite", "sqlite-wasm", "turso", "memory", "postgres", "mongodb"]).optional(),
2124
2124
  environmentId: z.string().optional(),
2125
- artifactPath: z.string().optional()
2125
+ artifactPath: z.string().optional(),
2126
+ /**
2127
+ * Project root directory. When set (typically by the CLI after locating
2128
+ * `objectstack.config.ts`), the default sqlite database is placed under
2129
+ * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2130
+ * `~/.objectstack/data/standalone.db`. This keeps per-project data
2131
+ * scoped to the project folder so different examples / apps don't
2132
+ * share a single database by accident.
2133
+ *
2134
+ * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2135
+ * precedence over this default.
2136
+ */
2137
+ projectRoot: z.string().optional()
2126
2138
  });
2127
2139
  function detectDriverFromUrl(dbUrl) {
2128
2140
  if (/^memory:\/\//i.test(dbUrl)) return "memory";
@@ -2147,7 +2159,7 @@ async function createStandaloneStack(config) {
2147
2159
  const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
2148
2160
  const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath2(cwd, "dist/objectstack.json");
2149
2161
  const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : resolvePath2(cwd, artifactPathInput);
2150
- const dbUrl = cfg.databaseUrl ?? process.env.OS_DATABASE_URL?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}`;
2162
+ const dbUrl = cfg.databaseUrl ?? process.env.OS_DATABASE_URL?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${resolvePath2(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}`);
2151
2163
  const dbAuthToken = cfg.databaseAuthToken ?? process.env.OS_DATABASE_AUTH_TOKEN?.trim() ?? process.env.TURSO_AUTH_TOKEN?.trim();
2152
2164
  const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
2153
2165
  const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
@@ -2365,6 +2377,13 @@ function toHeaders(input) {
2365
2377
  }
2366
2378
  return h;
2367
2379
  }
2380
+ function safeJsonParse2(s, fallback) {
2381
+ try {
2382
+ return JSON.parse(s);
2383
+ } catch {
2384
+ return fallback;
2385
+ }
2386
+ }
2368
2387
  async function tryFind(ql, object, where, limit = 100) {
2369
2388
  if (!ql || typeof ql.find !== "function") return [];
2370
2389
  try {
@@ -2380,6 +2399,7 @@ async function resolveExecutionContext(opts) {
2380
2399
  const ctx = {
2381
2400
  roles: [],
2382
2401
  permissions: [],
2402
+ systemPermissions: [],
2383
2403
  isSystem: false
2384
2404
  };
2385
2405
  let userId;
@@ -2488,10 +2508,38 @@ async function resolveExecutionContext(opts) {
2488
2508
  { id: { $in: Array.from(psIds) } },
2489
2509
  500
2490
2510
  );
2511
+ const tabRank = {
2512
+ hidden: 0,
2513
+ default_off: 1,
2514
+ default_on: 2,
2515
+ visible: 3
2516
+ };
2517
+ const mergedTabs = {};
2491
2518
  for (const ps of psRows) {
2492
2519
  if (ps.name && !ctx.permissions.includes(ps.name)) {
2493
2520
  ctx.permissions.push(ps.name);
2494
2521
  }
2522
+ const sysPerms = typeof ps.system_permissions === "string" ? safeJsonParse2(ps.system_permissions, []) : ps.system_permissions ?? ps.systemPermissions;
2523
+ if (Array.isArray(sysPerms)) {
2524
+ for (const p of sysPerms) {
2525
+ if (typeof p === "string" && !ctx.systemPermissions.includes(p)) {
2526
+ ctx.systemPermissions.push(p);
2527
+ }
2528
+ }
2529
+ }
2530
+ const tabs = typeof ps.tab_permissions === "string" ? safeJsonParse2(ps.tab_permissions, {}) : ps.tab_permissions ?? ps.tabPermissions;
2531
+ if (tabs && typeof tabs === "object") {
2532
+ for (const [app, val] of Object.entries(tabs)) {
2533
+ if (typeof val !== "string" || !(val in tabRank)) continue;
2534
+ const cur = mergedTabs[app];
2535
+ if (!cur || tabRank[val] > tabRank[cur]) {
2536
+ mergedTabs[app] = val;
2537
+ }
2538
+ }
2539
+ }
2540
+ }
2541
+ if (Object.keys(mergedTabs).length > 0) {
2542
+ ctx.tabPermissions = mergedTabs;
2495
2543
  }
2496
2544
  }
2497
2545
  return ctx;
@@ -3091,6 +3139,15 @@ var _HttpDispatcher = class _HttpDispatcher {
3091
3139
  async handleMetadata(path, _context, method, body, query) {
3092
3140
  const parts = path.replace(/^\/+/, "").split("/").filter(Boolean);
3093
3141
  if (parts[0] === "types") {
3142
+ const protocol = await this.resolveService("protocol");
3143
+ if (protocol && typeof protocol.getMetaTypes === "function") {
3144
+ try {
3145
+ const result = await protocol.getMetaTypes({});
3146
+ return { handled: true, response: this.success(result) };
3147
+ } catch (e) {
3148
+ console.warn("[HttpDispatcher] protocol.getMetaTypes() failed:", e?.message);
3149
+ }
3150
+ }
3094
3151
  const metadataService = await this.resolveService("metadata", _context.environmentId);
3095
3152
  if (metadataService && typeof metadataService.getRegisteredTypes === "function") {
3096
3153
  try {
@@ -3100,11 +3157,6 @@ var _HttpDispatcher = class _HttpDispatcher {
3100
3157
  console.warn("[HttpDispatcher] MetadataService.getRegisteredTypes() failed:", e.message);
3101
3158
  }
3102
3159
  }
3103
- const protocol = await this.resolveService("protocol");
3104
- if (protocol && typeof protocol.getMetaTypes === "function") {
3105
- const result = await protocol.getMetaTypes({});
3106
- return { handled: true, response: this.success(result) };
3107
- }
3108
3160
  return { handled: true, response: this.success({ types: ["object", "app", "plugin"] }) };
3109
3161
  }
3110
3162
  if (parts.length >= 3 && parts[parts.length - 1] === "published" && (!method || method === "GET")) {
@@ -3252,6 +3304,14 @@ var _HttpDispatcher = class _HttpDispatcher {
3252
3304
  return { handled: true, response: this.error("Not found", 404) };
3253
3305
  }
3254
3306
  if (parts.length === 0) {
3307
+ const protocol = await this.resolveService("protocol");
3308
+ if (protocol && typeof protocol.getMetaTypes === "function") {
3309
+ try {
3310
+ const result = await protocol.getMetaTypes({});
3311
+ return { handled: true, response: this.success(result) };
3312
+ } catch {
3313
+ }
3314
+ }
3255
3315
  const metadataService = await this.resolveService("metadata", _context.environmentId);
3256
3316
  if (metadataService && typeof metadataService.getRegisteredTypes === "function") {
3257
3317
  try {
@@ -3260,11 +3320,6 @@ var _HttpDispatcher = class _HttpDispatcher {
3260
3320
  } catch {
3261
3321
  }
3262
3322
  }
3263
- const protocol = await this.resolveService("protocol");
3264
- if (protocol && typeof protocol.getMetaTypes === "function") {
3265
- const result = await protocol.getMetaTypes({});
3266
- return { handled: true, response: this.success(result) };
3267
- }
3268
3323
  return { handled: true, response: this.success({ types: ["object", "app", "plugin"] }) };
3269
3324
  }
3270
3325
  return { handled: false };
@@ -5842,6 +5897,9 @@ function mountRouteOnServer(route, server, routePath, securityHeaders) {
5842
5897
  } else if (m === "delete" && typeof server.delete === "function") {
5843
5898
  server.delete(routePath, handler);
5844
5899
  return true;
5900
+ } else if (m === "patch" && typeof server.patch === "function") {
5901
+ server.patch(routePath, handler);
5902
+ return true;
5845
5903
  }
5846
5904
  return false;
5847
5905
  }