@objectstack/runtime 10.2.0 → 10.3.0

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
  environmentId: z.ZodOptional<z.ZodString>;
99
99
  artifactPath: z.ZodOptional<z.ZodString>;
100
100
  projectRoot: z.ZodOptional<z.ZodString>;
101
+ dev: z.ZodOptional<z.ZodBoolean>;
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
  environmentId: z.ZodOptional<z.ZodString>;
99
99
  artifactPath: z.ZodOptional<z.ZodString>;
100
100
  projectRoot: z.ZodOptional<z.ZodString>;
101
+ dev: z.ZodOptional<z.ZodBoolean>;
101
102
  }, z.core.$strip>;
102
103
  type StandaloneStackConfig = z.input<typeof StandaloneStackConfigSchema>;
103
104
  interface StandaloneStackResult {
package/dist/index.js CHANGED
@@ -1574,6 +1574,7 @@ async function createStandaloneStack(config) {
1574
1574
  );
1575
1575
  } else {
1576
1576
  const { createDefaultDatasourceDriverFactory } = await import("@objectstack/service-datasource");
1577
+ const factoryDev = cfg.dev ?? process.env.NODE_ENV === "development";
1577
1578
  let driverId;
1578
1579
  let driverConfig;
1579
1580
  if (dbDriver === "memory") {
@@ -1598,7 +1599,7 @@ async function createStandaloneStack(config) {
1598
1599
  }
1599
1600
  let driverHandle;
1600
1601
  try {
1601
- driverHandle = await createDefaultDatasourceDriverFactory().create({ driver: driverId, config: driverConfig });
1602
+ driverHandle = await createDefaultDatasourceDriverFactory({ dev: factoryDev }).create({ driver: driverId, config: driverConfig });
1602
1603
  } catch (err) {
1603
1604
  if (dbDriver === "mongodb") {
1604
1605
  throw new Error(
@@ -1683,7 +1684,14 @@ var init_standalone_stack = __esm({
1683
1684
  * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
1684
1685
  * precedence over this default.
1685
1686
  */
1686
- projectRoot: z.string().optional()
1687
+ projectRoot: z.string().optional(),
1688
+ /**
1689
+ * Dev gate for the sqlite driver factory's native-better-sqlite3 → wasm →
1690
+ * in-memory step-down (#2229). When omitted, defaults to
1691
+ * `process.env.NODE_ENV === 'development'`. In production a native load
1692
+ * failure is NOT silently swapped for wasm/mingo (fail-closed).
1693
+ */
1694
+ dev: z.boolean().optional()
1687
1695
  });
1688
1696
  }
1689
1697
  });
@@ -2165,14 +2173,12 @@ async function resolveExecutionContext(opts) {
2165
2173
  } else {
2166
2174
  ctx.org_user_ids = [userId];
2167
2175
  }
2168
- const upsRows = await tryFind(
2169
- ql,
2170
- "sys_user_permission_set",
2171
- tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId },
2172
- 100
2173
- );
2176
+ const upsRows = await tryFind(ql, "sys_user_permission_set", { user_id: userId }, 100);
2174
2177
  const psIds = new Set(
2175
- upsRows.map((r) => r.permission_set_id ?? r.permissionSetId).filter(Boolean)
2178
+ upsRows.filter((r) => {
2179
+ const org = r.organization_id ?? r.organizationId ?? null;
2180
+ return !(org && tenantId && org !== tenantId);
2181
+ }).map((r) => r.permission_set_id ?? r.permissionSetId).filter(Boolean)
2176
2182
  );
2177
2183
  if (ctx.roles.length > 0) {
2178
2184
  const roleRows = await tryFind(ql, "sys_role", { name: { $in: ctx.roles } }, 100);
@@ -4178,6 +4184,28 @@ var _HttpDispatcher = class _HttpDispatcher {
4178
4184
  if (!ql || typeof ql.executeAction !== "function") {
4179
4185
  return { handled: true, response: this.error("Data engine not available", 503) };
4180
4186
  }
4187
+ try {
4188
+ const actionSchema = (typeof ql.getSchema === "function" ? ql.getSchema(objectName) : void 0) ?? ql.registry?.getObject?.(objectName);
4189
+ const actionDef = Array.isArray(actionSchema?.actions) ? actionSchema.actions.find((a) => a?.name === actionName) : void 0;
4190
+ const required = Array.isArray(actionDef?.requiredPermissions) ? actionDef.requiredPermissions : [];
4191
+ if (required.length > 0) {
4192
+ const execCtx = _context?.executionContext;
4193
+ if (!execCtx?.isSystem) {
4194
+ const held = new Set(execCtx?.systemPermissions ?? []);
4195
+ const missing = required.filter((perm) => !held.has(perm));
4196
+ if (missing.length > 0) {
4197
+ return {
4198
+ handled: true,
4199
+ response: this.error(
4200
+ `Action '${actionName}' on '${objectName}' requires capability [${required.join(", ")}] \u2014 caller is missing [${missing.join(", ")}]`,
4201
+ 403
4202
+ )
4203
+ };
4204
+ }
4205
+ }
4206
+ }
4207
+ } catch {
4208
+ }
4181
4209
  const tryExecute = async (obj) => {
4182
4210
  return ql.executeAction(obj, actionName, actionContext);
4183
4211
  };
@@ -5240,6 +5268,14 @@ function createDispatcherPlugin(config = {}) {
5240
5268
  errorResponse(err, res);
5241
5269
  }
5242
5270
  });
5271
+ server.get(`${prefix}/ready`, async (_req, res) => {
5272
+ try {
5273
+ const result = await dispatcher.dispatch("GET", "/ready", void 0, {}, { request: _req });
5274
+ sendResult(result, res);
5275
+ } catch (err) {
5276
+ errorResponse(err, res);
5277
+ }
5278
+ });
5243
5279
  server.post(`${prefix}/auth/login`, async (req, res) => {
5244
5280
  try {
5245
5281
  const result = await dispatcher.handleAuth("login", "POST", req.body, { request: req });