@objectstack/runtime 7.6.0 → 7.8.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
@@ -324,6 +324,24 @@ var init_seed_loader = __esm({
324
324
  for (const ref of objectRefs) {
325
325
  const fieldValue = record[ref.field];
326
326
  if (fieldValue === void 0 || fieldValue === null) continue;
327
+ if (typeof fieldValue === "object") {
328
+ const wrapped = fieldValue.externalId;
329
+ const hint = wrapped !== void 0 ? ` Pass the natural key directly: ${ref.field}: ${JSON.stringify(wrapped)}.` : ` Pass the target's ${ref.targetField} value as a plain string.`;
330
+ const error = {
331
+ sourceObject: objectName,
332
+ field: ref.field,
333
+ targetObject: ref.targetObject,
334
+ targetField: ref.targetField,
335
+ attemptedValue: fieldValue,
336
+ recordIndex: i,
337
+ message: `Invalid reference for ${objectName}.${ref.field}: expected a ${ref.targetObject}.${ref.targetField} natural-key string but got an object.${hint}`
338
+ };
339
+ errors.push(error);
340
+ allErrors.push(error);
341
+ this.logger.warn(`[SeedLoader] ${error.message}`, { recordIndex: i });
342
+ record[ref.field] = null;
343
+ continue;
344
+ }
327
345
  if (typeof fieldValue !== "string" || this.looksLikeInternalId(fieldValue)) continue;
328
346
  const targetMap = insertedRecords.get(ref.targetObject);
329
347
  const resolvedId = targetMap?.get(String(fieldValue));
@@ -3607,6 +3625,23 @@ var _HttpDispatcher = class _HttpDispatcher {
3607
3625
  return { handled: true, response: this.error(e.message, 404) };
3608
3626
  }
3609
3627
  }
3628
+ if (parts.length === 1 && parts[0] === "_drafts" && (!method || method.toUpperCase() === "GET")) {
3629
+ const protocol = await this.resolveService("protocol");
3630
+ if (protocol && typeof protocol.listDrafts === "function") {
3631
+ try {
3632
+ const organizationId = await this.resolveActiveOrganizationId(_context);
3633
+ const data = await protocol.listDrafts({
3634
+ packageId: query?.packageId || void 0,
3635
+ type: query?.type || void 0,
3636
+ organizationId
3637
+ });
3638
+ return { handled: true, response: this.success(data) };
3639
+ } catch (e) {
3640
+ return { handled: true, response: this.error(e.message, 500) };
3641
+ }
3642
+ }
3643
+ return { handled: true, response: this.error("Draft listing not supported", 501) };
3644
+ }
3610
3645
  if (parts.length === 1) {
3611
3646
  const typeOrName = parts[0];
3612
3647
  const packageId = query?.package || void 0;
@@ -3906,7 +3941,15 @@ var _HttpDispatcher = class _HttpDispatcher {
3906
3941
  return { handled: true, response: this.success({ packages, total: packages.length }) };
3907
3942
  }
3908
3943
  if (parts.length === 0 && m === "POST") {
3909
- const pkg = registry.installPackage(body.manifest || body, body.settings);
3944
+ const manifest = body.manifest || body;
3945
+ let pkg;
3946
+ const protocolSvc = await this.resolveService("protocol").catch(() => null);
3947
+ if (protocolSvc && typeof protocolSvc.installPackage === "function") {
3948
+ const out = await protocolSvc.installPackage({ manifest, settings: body.settings });
3949
+ pkg = out?.package ?? out;
3950
+ } else {
3951
+ pkg = registry.installPackage(manifest, body.settings);
3952
+ }
3910
3953
  const res = this.success(pkg);
3911
3954
  res.status = 201;
3912
3955
  return { handled: true, response: res };
@@ -3942,6 +3985,24 @@ var _HttpDispatcher = class _HttpDispatcher {
3942
3985
  }
3943
3986
  return { handled: true, response: this.error("Metadata service not available", 503) };
3944
3987
  }
3988
+ if (parts.length === 2 && parts[1] === "publish-drafts" && m === "POST") {
3989
+ const id = decodeURIComponent(parts[0]);
3990
+ const protocol = await this.resolveService("protocol");
3991
+ if (protocol && typeof protocol.publishPackageDrafts === "function") {
3992
+ try {
3993
+ const organizationId = await this.resolveActiveOrganizationId(_context);
3994
+ const result = await protocol.publishPackageDrafts({
3995
+ packageId: id,
3996
+ ...organizationId ? { organizationId } : {},
3997
+ ...body?.actor ? { actor: body.actor } : {}
3998
+ });
3999
+ return { handled: true, response: this.success(result) };
4000
+ } catch (e) {
4001
+ return { handled: true, response: this.error(e.message, e.statusCode || 500) };
4002
+ }
4003
+ }
4004
+ return { handled: true, response: this.error("Draft publishing not supported", 501) };
4005
+ }
3945
4006
  if (parts.length === 2 && parts[1] === "revert" && m === "POST") {
3946
4007
  const id = decodeURIComponent(parts[0]);
3947
4008
  const metadataService = await this.getService(import_system2.CoreServiceName.enum.metadata);
@@ -5441,6 +5502,14 @@ function createDispatcherPlugin(config = {}) {
5441
5502
  errorResponse(err, res);
5442
5503
  }
5443
5504
  });
5505
+ server.post(`${prefix}/packages/:id/publish-drafts`, async (req, res) => {
5506
+ try {
5507
+ const result = await dispatcher.handlePackages(`/${req.params.id}/publish-drafts`, "POST", req.body, {}, { request: req });
5508
+ sendResult(result, res);
5509
+ } catch (err) {
5510
+ errorResponse(err, res);
5511
+ }
5512
+ });
5444
5513
  server.post(`${prefix}/packages/:id/revert`, async (req, res) => {
5445
5514
  try {
5446
5515
  const result = await dispatcher.handlePackages(`/${req.params.id}/revert`, "POST", req.body, {}, { request: req });
@@ -7453,6 +7522,61 @@ var AuthProxyPlugin = class {
7453
7522
  return c.text(`sso-exchange failed: ${err?.message ?? String(err)}`, 500);
7454
7523
  }
7455
7524
  }
7525
+ if (c.req.method === "POST" && subPath === "set-initial-password") {
7526
+ try {
7527
+ let body = {};
7528
+ try {
7529
+ body = await c.req.json();
7530
+ } catch {
7531
+ body = {};
7532
+ }
7533
+ const newPassword = body?.newPassword;
7534
+ if (typeof newPassword !== "string" || newPassword.length === 0) {
7535
+ return c.json({ success: false, error: { code: "invalid_request", message: "newPassword is required" } }, 400);
7536
+ }
7537
+ if (typeof authSvc?.getAuthContext !== "function") {
7538
+ return c.json({ success: false, error: { code: "unavailable", message: "Auth context unavailable" } }, 503);
7539
+ }
7540
+ let userId;
7541
+ try {
7542
+ const api = typeof authSvc.getApi === "function" ? await authSvc.getApi() : null;
7543
+ const session = await api?.getSession?.({ headers: c.req.raw.headers });
7544
+ userId = session?.user?.id ? String(session.user.id) : void 0;
7545
+ } catch {
7546
+ }
7547
+ if (!userId) {
7548
+ return c.json({ success: false, error: { code: "unauthorized", message: "Sign in first" } }, 401);
7549
+ }
7550
+ const setPwCtx = await authSvc.getAuthContext();
7551
+ if (!setPwCtx?.internalAdapter || !setPwCtx?.password) {
7552
+ return c.json({ success: false, error: { code: "unavailable", message: "Auth context unavailable" } }, 503);
7553
+ }
7554
+ const minLen = setPwCtx.password?.config?.minPasswordLength ?? 8;
7555
+ const maxLen = setPwCtx.password?.config?.maxPasswordLength ?? 128;
7556
+ if (newPassword.length < minLen) {
7557
+ return c.json({ success: false, error: { code: "password_too_short", message: `Password must be at least ${minLen} characters` } }, 400);
7558
+ }
7559
+ if (newPassword.length > maxLen) {
7560
+ return c.json({ success: false, error: { code: "password_too_long", message: `Password must be at most ${maxLen} characters` } }, 400);
7561
+ }
7562
+ const accounts = await setPwCtx.internalAdapter.findAccounts(userId);
7563
+ const existingCredential = accounts?.find?.((a) => a.providerId === "credential" && a.password);
7564
+ if (existingCredential) {
7565
+ return c.json({ success: false, error: { code: "credential_account_exists", message: "A local password is already set for this account. Use change-password instead." } }, 409);
7566
+ }
7567
+ const passwordHash = await setPwCtx.password.hash(newPassword);
7568
+ await setPwCtx.internalAdapter.createAccount({
7569
+ userId,
7570
+ providerId: "credential",
7571
+ accountId: userId,
7572
+ password: passwordHash
7573
+ });
7574
+ return c.json({ success: true });
7575
+ } catch (err) {
7576
+ ctx.logger?.error?.("[AuthProxyPlugin] set-initial-password failed", err instanceof Error ? err : new Error(String(err)));
7577
+ return c.json({ success: false, error: { code: "set_password_failed", message: String(err?.message ?? err) } }, 500);
7578
+ }
7579
+ }
7456
7580
  const fn = await resolveAuthHandler(authSvc);
7457
7581
  if (!fn) {
7458
7582
  return c.json({ error: "auth_service_unavailable", environmentId }, 503);
@@ -8167,7 +8291,17 @@ async function createObjectOSStack(config) {
8167
8291
  };
8168
8292
  const enginePlugins = await createHostEnginePlugins();
8169
8293
  return {
8170
- plugins: [...enginePlugins, new ObjectOSEnvironmentPlugin(merged), new AuthProxyPlugin(), new MarketplaceProxyPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl }), new RuntimeConfigPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl, installLocal: false })],
8294
+ plugins: [
8295
+ ...enginePlugins,
8296
+ new ObjectOSEnvironmentPlugin(merged),
8297
+ new AuthProxyPlugin(),
8298
+ new MarketplaceProxyPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl }),
8299
+ new RuntimeConfigPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl, installLocal: false }),
8300
+ // Host-supplied product/policy plugins (the official seam — see
8301
+ // ObjectOSStackConfig.extraPlugins). Appended last so they mount
8302
+ // after the framework defaults.
8303
+ ...config.extraPlugins ?? []
8304
+ ],
8171
8305
  api: {
8172
8306
  enableProjectScoping: true,
8173
8307
  projectResolution: "auto",