@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.cjs CHANGED
@@ -1593,6 +1593,7 @@ async function createStandaloneStack(config) {
1593
1593
  );
1594
1594
  } else {
1595
1595
  const { createDefaultDatasourceDriverFactory } = await import("@objectstack/service-datasource");
1596
+ const factoryDev = cfg.dev ?? process.env.NODE_ENV === "development";
1596
1597
  let driverId;
1597
1598
  let driverConfig;
1598
1599
  if (dbDriver === "memory") {
@@ -1617,7 +1618,7 @@ async function createStandaloneStack(config) {
1617
1618
  }
1618
1619
  let driverHandle;
1619
1620
  try {
1620
- driverHandle = await createDefaultDatasourceDriverFactory().create({ driver: driverId, config: driverConfig });
1621
+ driverHandle = await createDefaultDatasourceDriverFactory({ dev: factoryDev }).create({ driver: driverId, config: driverConfig });
1621
1622
  } catch (err) {
1622
1623
  if (dbDriver === "mongodb") {
1623
1624
  throw new Error(
@@ -1707,7 +1708,14 @@ var init_standalone_stack = __esm({
1707
1708
  * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
1708
1709
  * precedence over this default.
1709
1710
  */
1710
- projectRoot: import_zod.z.string().optional()
1711
+ projectRoot: import_zod.z.string().optional(),
1712
+ /**
1713
+ * Dev gate for the sqlite driver factory's native-better-sqlite3 → wasm →
1714
+ * in-memory step-down (#2229). When omitted, defaults to
1715
+ * `process.env.NODE_ENV === 'development'`. In production a native load
1716
+ * failure is NOT silently swapped for wasm/mingo (fail-closed).
1717
+ */
1718
+ dev: import_zod.z.boolean().optional()
1711
1719
  });
1712
1720
  }
1713
1721
  });
@@ -2233,14 +2241,12 @@ async function resolveExecutionContext(opts) {
2233
2241
  } else {
2234
2242
  ctx.org_user_ids = [userId];
2235
2243
  }
2236
- const upsRows = await tryFind(
2237
- ql,
2238
- "sys_user_permission_set",
2239
- tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId },
2240
- 100
2241
- );
2244
+ const upsRows = await tryFind(ql, "sys_user_permission_set", { user_id: userId }, 100);
2242
2245
  const psIds = new Set(
2243
- upsRows.map((r) => r.permission_set_id ?? r.permissionSetId).filter(Boolean)
2246
+ upsRows.filter((r) => {
2247
+ const org = r.organization_id ?? r.organizationId ?? null;
2248
+ return !(org && tenantId && org !== tenantId);
2249
+ }).map((r) => r.permission_set_id ?? r.permissionSetId).filter(Boolean)
2244
2250
  );
2245
2251
  if (ctx.roles.length > 0) {
2246
2252
  const roleRows = await tryFind(ql, "sys_role", { name: { $in: ctx.roles } }, 100);
@@ -4246,6 +4252,28 @@ var _HttpDispatcher = class _HttpDispatcher {
4246
4252
  if (!ql || typeof ql.executeAction !== "function") {
4247
4253
  return { handled: true, response: this.error("Data engine not available", 503) };
4248
4254
  }
4255
+ try {
4256
+ const actionSchema = (typeof ql.getSchema === "function" ? ql.getSchema(objectName) : void 0) ?? ql.registry?.getObject?.(objectName);
4257
+ const actionDef = Array.isArray(actionSchema?.actions) ? actionSchema.actions.find((a) => a?.name === actionName) : void 0;
4258
+ const required = Array.isArray(actionDef?.requiredPermissions) ? actionDef.requiredPermissions : [];
4259
+ if (required.length > 0) {
4260
+ const execCtx = _context?.executionContext;
4261
+ if (!execCtx?.isSystem) {
4262
+ const held = new Set(execCtx?.systemPermissions ?? []);
4263
+ const missing = required.filter((perm) => !held.has(perm));
4264
+ if (missing.length > 0) {
4265
+ return {
4266
+ handled: true,
4267
+ response: this.error(
4268
+ `Action '${actionName}' on '${objectName}' requires capability [${required.join(", ")}] \u2014 caller is missing [${missing.join(", ")}]`,
4269
+ 403
4270
+ )
4271
+ };
4272
+ }
4273
+ }
4274
+ }
4275
+ } catch {
4276
+ }
4249
4277
  const tryExecute = async (obj) => {
4250
4278
  return ql.executeAction(obj, actionName, actionContext);
4251
4279
  };
@@ -5298,6 +5326,14 @@ function createDispatcherPlugin(config = {}) {
5298
5326
  errorResponse(err, res);
5299
5327
  }
5300
5328
  });
5329
+ server.get(`${prefix}/ready`, async (_req, res) => {
5330
+ try {
5331
+ const result = await dispatcher.dispatch("GET", "/ready", void 0, {}, { request: _req });
5332
+ sendResult(result, res);
5333
+ } catch (err) {
5334
+ errorResponse(err, res);
5335
+ }
5336
+ });
5301
5337
  server.post(`${prefix}/auth/login`, async (req, res) => {
5302
5338
  try {
5303
5339
  const result = await dispatcher.handleAuth("login", "POST", req.body, { request: req });