diff --git a/.changeset/objectstack-17-7-0.md b/.changeset/objectstack-17-7-0.md new file mode 100644 index 00000000..760213f9 --- /dev/null +++ b/.changeset/objectstack-17-7-0.md @@ -0,0 +1,100 @@ +--- +'hotcrm': minor +--- + +Upgrade the ObjectStack platform to 17.7.0 + +All 21 `@objectstack/*` dependencies move 17.6.0 → 17.7.0 together — 20 in +`dependencies`, `@objectstack/formula` in `devDependencies` — pinned exact, no +caret. `specVersion` and `engines.protocol` follow to `^17.7.0`, in +`objectstack.manifest.json` and in the stack manifest in `objectstack.config.ts`. +17.7.0 still implements protocol 17, so both declarations stay on major 17. +`pnpm-lock.yaml` was regenerated by `pnpm install` against the public registry: +706 `packages:` entries before, 704 after. The 54 `@objectstack/*` and +`create-objectstack` keys moved 1:1, `@noble/ciphers` and `jose` left the tree, and +no third-party package changed version. The install still prints the peer note +17.6.0 printed (`better-auth` asks for `better-sqlite3@^12`; 13.0.3 is installed). + +The platform changes that reached this app: + +- **The screen-flow dialogs speak the reader's language.** The 17.7.0 console's + flow runner reads the `flows` translation group (the spec's liveness row for it + is now `live`), and `os lint` reports a missing key as `i18n/missing-flow`. It + reported 108 on this app: the seven screen flows' labels, screen titles and + field labels, in zh-CN, es-ES and ja-JP. All 108 are translated, in each + locale's `app.ts`, using the words the packs already use for the same objects + and actions. A screen with no authored title shows its flow's label, so each + `screen_1.title` repeats the flow label. The quote dialog's discount label is + interpolated from `QUOTE_DISCOUNT_CEILING`, so the ceiling is still written in + one place only (#1711). **What readers will see:** a zh-CN seller opening + *Escalate Case*, *Close Case*, *Claim Case*, *Convert Lead*, *Schedule + Follow-up*, *Generate Quote* or *Enroll Members* now reads Chinese titles and + field labels where they read English. Six of the seven were opened in a zh-CN + browser; *Claim Case* is offered only on an unowned case, and the demo data + holds none. Select-option labels and screen + descriptions on these dialogs stay as authored: a screen field's options are + not a translatable key on the platform (`FLOW_SCREEN_FIELD_NO_OPTIONS`). This + closes #1210 and #1975. +- **The lead page's Tasks list drops three action ids that named nothing.** + 17.7.0 adds an author-time rule (`action-name-undefined`) that refuses a + `record:related_list` action id the related object does not define. The lead + page's Tasks list named `new_task`, `edit` and `complete`, and `crm_task` + defines no action, so none of them ever drew a button. The 17.7.0 console would + draw a refusal notice above the list for them instead. The ids are removed. + **What readers will see:** no change. The list's own *New* and *View all* + affordances are drawn by the platform and stay. +- **The contact mailing-address conversion (#1836) works on 17.7.0.** 17.7.0 + serves declared fields only, so no REST read returns a retired field's + leftover column any more. The conversion script read the five old `mailing_*` + columns that way, and on 17.7.0 it would have found nothing to convert. It now + takes `--unmapped FILE`, the JSON that the platform's new operator-only + `os migrate unmapped-columns --object crm_contact --json` prints, and still + writes through the REST API. Measured on 17.7.0 against a contact whose + `mailing_street` column held a value: the REST read carried no `mailing_*` + key; the command read it; the script converted it, read the address back, and + a second run reported it already converted. +- **Claims that named 17.6.0 as the current pin are re-scoped.** The *What's + new* platform line and `docs/STATUS.md` name 17.7.0. A flow comment, a + composition comment, a maintainer-doc line and two test comments that read as + "17.6.0 is the pin" now date themselves. Claims written as "measured on + 17.6.0" are dated truth and stay as they are. None was re-measured on 17.7.0 + except the REST query door the backfill test models, which is unchanged. + +The test suite needed three adjustments, all to its harnesses: the engine now +refuses an object name its registry does not hold (objectstack#21545), so nine +files register the platform identity objects `plugin-auth` registers in a real +boot; a by-id write to a row the caller cannot read now answers +`RECORD_NOT_FOUND` instead of a permission error (objectstack#21812), so the +reach tests expect that for unreadable rows, still refused and still unwritten; +and the share-link test's response stub gains the `header()` the 17.7.0 route +calls. No assertion was loosened. + +The upgrade was exercised in place on a database that HotCRM on 17.6.0 had +created, seeded and written to, including an opportunity whose amount opened an +approval request. `os migrate meta --stored` found no stored metadata row, so it +attests nothing here; `os migrate audit-metadata-bodies` found nothing to +rewrite; `os migrate plan` reported the schema in sync. The 17.7.0 server +booted on that database with no errors, the 17.6.0 records opened, and the +approval request opened on 17.6.0 was decided on 17.7.0 by an administrator's +override. A fresh boot seeded the demo data, and a browser pass covered sign-in, +dashboards, lists, record pages, record creation, a screen flow run, reports, +the approvals inbox, both public forms and the zh-CN dialogs. + +**What operators should know:** + +- **The public Web-to-Lead and Web-to-Case forms keep working.** 17.7.0 serves + a form anonymously only when its `sharing` sets `enabled: true`, and both + forms already did. An anonymous Web-to-Lead submission on 17.7.0 created its + lead. +- **Upgrading a deployment from HotCRM 3.1.0 moves contact addresses with the + new route.** Before `os migrate apply --allow-destructive`, run + `objectstack migrate unmapped-columns --object crm_contact --json > FILE` from + the project root, then the conversion script with `--unmapped FILE`. +- **A write to a record the caller cannot see answers 404 `RECORD_NOT_FOUND`**, + where it answered 403 before. An integration that branches on 403 for this + case reads a 404 now. +- **Not exercised here:** the release's rotate-after-first-boot step for flow + secrets. HotCRM's two billing-handoff flows carry a `signingSecret` only when + the build sets `HOTCRM_BILLING_SIGNING_SECRET`, and no run of this upgrade set + it. A deployment that does should rotate that secret after the first 17.7.0 + boot, as the 17.7.0 upgrade checklist says. diff --git a/content/docs/whats-new.mdx b/content/docs/whats-new.mdx index 38a54d53..46c57cac 100644 --- a/content/docs/whats-new.mdx +++ b/content/docs/whats-new.mdx @@ -71,8 +71,8 @@ http://localhost:4001 and create the first admin account. refuses the load up front with a structured diagnostic instead of failing deep in a schema parse. -Since 3.1.0 was cut, the app has moved to **ObjectStack 17.6.0** (manifest range -`^17.6.0`). That move ships with the next HotCRM release; until then, 3.1.0 is the +Since 3.1.0 was cut, the app has moved to **ObjectStack 17.7.0** (manifest range +`^17.7.0`). That move ships with the next HotCRM release; until then, 3.1.0 is the release that runs on 17.4.0. > **This page does not keep a second release table.** The release-by-release diff --git a/content/docs/whats-new.zh-Hans.mdx b/content/docs/whats-new.zh-Hans.mdx index 8f097dab..ad20a08f 100644 --- a/content/docs/whats-new.zh-Hans.mdx +++ b/content/docs/whats-new.zh-Hans.mdx @@ -51,7 +51,7 @@ HOTCRM_TOKEN=... ./scripts/wow1-live-schema.sh 应用清单声明了与之匹配的 `^17.4.0` 协议区间,因此协议大版本不同的运行时会在 装载之初就带着结构化诊断拒绝加载,而不是在某次 schema 解析的深处才失败。 -3.1.0 发布之后,应用已迁移到 **ObjectStack 17.6.0**(清单区间 `^17.6.0`)。这次迁移随下一个 +3.1.0 发布之后,应用已迁移到 **ObjectStack 17.7.0**(清单区间 `^17.7.0`)。这次迁移随下一个 HotCRM 版本发布;在那之前,运行在 17.4.0 上的发布版本仍是 3.1.0。 > **这一页不维护第二张发布表。** 逐版本的发布历史在仓库的 `CHANGELOG.md` 里,由每个 diff --git a/content/docs/whats-new.zh-Hant.mdx b/content/docs/whats-new.zh-Hant.mdx index 853b61b0..11ca75da 100644 --- a/content/docs/whats-new.zh-Hant.mdx +++ b/content/docs/whats-new.zh-Hant.mdx @@ -53,7 +53,7 @@ HOTCRM_TOKEN=... ./scripts/wow1-live-schema.sh 應用清單宣告了與之相符的 `^17.4.0` 協定區間,因此協定大版本不同的執行時會在 載入之初就帶著結構化診斷拒絕載入,而不是在某次 schema 解析的深處才失敗。 -3.1.0 發行之後,應用已遷移到 **ObjectStack 17.6.0**(清單區間 `^17.6.0`)。這次遷移隨下一個 +3.1.0 發行之後,應用已遷移到 **ObjectStack 17.7.0**(清單區間 `^17.7.0`)。這次遷移隨下一個 HotCRM 版本發行;在那之前,執行在 17.4.0 上的發行版本仍是 3.1.0。 > **這一頁不維護第二張發行表。** 逐版本的發行歷史在儲存庫的 `CHANGELOG.md` 裡,由每個 diff --git a/docs/STATUS.md b/docs/STATUS.md index fd1a59da..98967ad3 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -73,7 +73,7 @@ pnpm verify | --- | --- | | Node.js | `^22.11 \|\| ^24 \|\| >=26` | | pnpm | `>=10.0.0` | -| ObjectStack packages | `17.6.0` | +| ObjectStack packages | `17.7.0` | | Local dev port | `4001` | Each row above is asserted against `package.json` (`engines`, the `@objectstack/*` diff --git a/docs/architecture/module-split-plan.md b/docs/architecture/module-split-plan.md index 2486fe11..e4b45471 100644 --- a/docs/architecture/module-split-plan.md +++ b/docs/architecture/module-split-plan.md @@ -360,7 +360,7 @@ would otherwise slug the heading to `#上游缺口--upstream-gaps` — the exact [objectstack#14430](https://github.com/objectstack-ai/objectstack/issues/14430). - An objectstack release carrying both, and the version bump in this repository. HotCRM was pinned to `@objectstack/*` 17.4.0 when this was written (PR #1814, #1807) and moved to 17.5.0, - then 17.6.0, after it (this plan's own measurements were taken at the 17.2.0 pin and are labelled as such). + then 17.6.0 and 17.7.0, after it (this plan's own measurements were taken at the 17.2.0 pin and are labelled as such). Merged upstream is not the same as available in the pin (AGENTS.md, *Platform Upgrades*). diff --git a/objectstack.composition.ts b/objectstack.composition.ts index 8a4f26e4..2223c9f4 100644 --- a/objectstack.composition.ts +++ b/objectstack.composition.ts @@ -349,8 +349,8 @@ export { CrmPositions }; * The PLATFORM does it, at the only moment it can: when the seed settles, * `@objectstack/plugin-security` re-runs its seed-ownership claim on * `app:seeded` and hands every ownerless row of every object carrying - * `owner_id` to the first platform administrator (objectstack#17872, in the - * 17.6.0 pin). No HotCRM flow is involved. The `demo_bootstrap` sweep that used + * `owner_id` to the first platform administrator (objectstack#17872, shipped in + * 17.6.0). No HotCRM flow is involved. The `demo_bootstrap` sweep that used * to do this every ten minutes was retired once a fresh boot measured that * claim leaving all twelve seeded owner-scoped objects at zero ownerless rows * with the sweep disabled (#1892). diff --git a/objectstack.config.ts b/objectstack.config.ts index 7c3384f4..c6a4252f 100644 --- a/objectstack.config.ts +++ b/objectstack.config.ts @@ -76,7 +76,7 @@ export default defineStack({ // enforces that pairing against `objectstack.manifest.json` instead of // trusting this comment, because two platform upgrades in a row (rc.2, then // rc.3) moved the manifest and left this line behind (#728). - engines: { protocol: '^17.6.0' }, + engines: { protocol: '^17.7.0' }, }, // ─── Platform capabilities this app needs ───────────────────────── diff --git a/objectstack.manifest.json b/objectstack.manifest.json index 0d910b14..858104fb 100644 --- a/objectstack.manifest.json +++ b/objectstack.manifest.json @@ -1,9 +1,9 @@ { "$schema": "https://schemas.objectstack.dev/template-manifest.json", "name": "hotcrm", - "specVersion": "^17.6.0", + "specVersion": "^17.7.0", "engines": { - "protocol": "^17.6.0" + "protocol": "^17.7.0" }, "manifestId": "app.objectstack.hotcrm", "displayName": "HotCRM", diff --git a/package.json b/package.json index a9dc56e9..95deedc4 100644 --- a/package.json +++ b/package.json @@ -36,33 +36,33 @@ }, "packageManager": "pnpm@10.33.0", "dependencies": { - "@objectstack/account": "17.6.0", - "@objectstack/cli": "17.6.0", - "@objectstack/core": "17.6.0", - "@objectstack/driver-memory": "17.6.0", - "@objectstack/driver-sql": "17.6.0", - "@objectstack/driver-sqlite-wasm": "17.6.0", - "@objectstack/metadata": "17.6.0", - "@objectstack/objectql": "17.6.0", - "@objectstack/platform-objects": "17.6.0", - "@objectstack/plugin-approvals": "17.6.0", - "@objectstack/plugin-auth": "17.6.0", - "@objectstack/plugin-security": "17.6.0", - "@objectstack/plugin-sharing": "17.6.0", - "@objectstack/runtime": "17.6.0", - "@objectstack/service-analytics": "17.6.0", - "@objectstack/service-automation": "17.6.0", - "@objectstack/service-messaging": "17.6.0", - "@objectstack/service-storage": "17.6.0", - "@objectstack/spec": "17.6.0", - "@objectstack/trigger-record-change": "17.6.0" + "@objectstack/account": "17.7.0", + "@objectstack/cli": "17.7.0", + "@objectstack/core": "17.7.0", + "@objectstack/driver-memory": "17.7.0", + "@objectstack/driver-sql": "17.7.0", + "@objectstack/driver-sqlite-wasm": "17.7.0", + "@objectstack/metadata": "17.7.0", + "@objectstack/objectql": "17.7.0", + "@objectstack/platform-objects": "17.7.0", + "@objectstack/plugin-approvals": "17.7.0", + "@objectstack/plugin-auth": "17.7.0", + "@objectstack/plugin-security": "17.7.0", + "@objectstack/plugin-sharing": "17.7.0", + "@objectstack/runtime": "17.7.0", + "@objectstack/service-analytics": "17.7.0", + "@objectstack/service-automation": "17.7.0", + "@objectstack/service-messaging": "17.7.0", + "@objectstack/service-storage": "17.7.0", + "@objectstack/spec": "17.7.0", + "@objectstack/trigger-record-change": "17.7.0" }, "optionalDependencies": { "better-sqlite3": "^13.0.3" }, "devDependencies": { "@changesets/cli": "^3.0.3", - "@objectstack/formula": "17.6.0", + "@objectstack/formula": "17.7.0", "@playwright/test": "^1.63.0", "@vitest/coverage-v8": "^4.1.10", "fumadocs-core": "16.15.14", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ff9699e..bc6d251e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,72 +9,72 @@ importers: .: dependencies: '@objectstack/account': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/cli': - specifier: 17.6.0 - version: 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) '@objectstack/core': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 '@objectstack/driver-memory': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 '@objectstack/driver-sql': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 '@objectstack/driver-sqlite-wasm': - specifier: 17.6.0 - version: 17.6.0(better-sqlite3@13.0.3) + specifier: 17.7.0 + version: 17.7.0(better-sqlite3@13.0.3) '@objectstack/metadata': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/objectql': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/platform-objects': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/plugin-approvals': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/plugin-auth': - specifier: 17.6.0 - version: 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) '@objectstack/plugin-security': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/plugin-sharing': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/runtime': - specifier: 17.6.0 - version: 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) '@objectstack/service-analytics': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 '@objectstack/service-automation': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/service-messaging': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/service-storage': - specifier: 17.6.0 - version: 17.6.0(vitest@4.1.10) + specifier: 17.7.0 + version: 17.7.0(vitest@4.1.10) '@objectstack/spec': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 '@objectstack/trigger-record-change': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 devDependencies: '@changesets/cli': specifier: ^3.0.3 version: 3.0.3 '@objectstack/formula': - specifier: 17.6.0 - version: 17.6.0 + specifier: 17.7.0 + version: 17.7.0 '@playwright/test': specifier: ^1.63.0 version: 1.63.0 @@ -555,10 +555,6 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@noble/ciphers@2.3.0': - resolution: {integrity: sha512-Clu/xdfgVTf9o7ngLOURaxePwR0j8sjclKEtVij10/jGulwFsPWCvvRgG/XjUVf8Nei+jLG6uwyXzUTGY1DQrw==} - engines: {node: '>= 20.19.0'} - '@noble/ciphers@2.4.0': resolution: {integrity: sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==} engines: {node: '>= 20.19.0'} @@ -570,45 +566,45 @@ packages: '@nodable/entities@3.0.0': resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} - '@objectstack/account@17.6.0': - resolution: {integrity: sha512-QHDEwjBfnyFQVEDHplGayb5IBY3PGKOub+wns2crV3JpCTKBlXOqCGiTRxsckwFUsM4EUweZ6xDjopphJ6gU5A==} + '@objectstack/account@17.7.0': + resolution: {integrity: sha512-nPeR21ndVZajDaiy/g0RBupG3NGuDXlzN7daag+cxl+iDKS4TzWvfqnp8Pnr8UnRJ+Et93CSaVLjUZRxHhBVow==} engines: {node: '>=22.0.0'} - '@objectstack/cli@17.6.0': - resolution: {integrity: sha512-DPEoQwIWArXyzpgn6Ni8eMLgVhQ+kGB+bEHPIluGVj+QnUpZ6imn5uf2n1eBWURKMgNkSf3RmCPQcb6pLox7ig==} + '@objectstack/cli@17.7.0': + resolution: {integrity: sha512-WTJ5B/uYSmqlMmqiGy7Acu8M45kHfouothcedRV1XldbKE+1lDGp+Gxg7bNXgqoLU/dmuvYz3JvMs2TPedKNkQ==} engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@objectstack/driver-turso': ^17.6.0 + '@objectstack/driver-turso': ^17.7.0 peerDependenciesMeta: '@objectstack/driver-turso': optional: true - '@objectstack/client@17.6.0': - resolution: {integrity: sha512-ZvhtjximG+nQNeC8v0Ed/FRdI5xcGQLJzxUtKlqvJJ6I3ueqBmOs8zHSoCa1vyMbctjBuzLRKxUeM9cUn9LTuA==} + '@objectstack/client@17.7.0': + resolution: {integrity: sha512-PFnr58tb1usCSMP+jNyuMBn9a6fEcaVFOiGRox9B88VQvttXo99akGzI8utFX8DsEobLQbh9YZBtXR51VI+JQg==} engines: {node: '>=22.0.0'} - '@objectstack/cloud-connection@17.6.0': - resolution: {integrity: sha512-Dlp+Yd1jlWpUKK9OCHOSQEn0/3njV4Bdl/VwH8lxPAam2h/PbKGR+Z3N2ShFoIMRFtpPea++gUOZnuQBz3vVXw==} + '@objectstack/cloud-connection@17.7.0': + resolution: {integrity: sha512-NGBWESNZVX63NIwiwZOF8tNlsqw6KQARtET6oHd+BaTLzRs9Bk1bCkRifoDgrlom9029rRgWM/v80JiOPWgkGQ==} engines: {node: '>=22.0.0'} - '@objectstack/console@17.6.0': - resolution: {integrity: sha512-+XqinpHCkgCI7Kho7LfhEeBc51s5ZB+V8VV0Rqa2ipkUCpDU+m4iS1vVb57tdR68wDnLsjuxUO04j2SccQCmNg==} + '@objectstack/console@17.7.0': + resolution: {integrity: sha512-4Z8Fy47VHzHtLk82sxf5I6J3SLUhT5NetZLI1YccBvkyMe4stzwx7GKCFAzK+MSKGE3Arv+PGIdqCuvNCd4neA==} - '@objectstack/core@17.6.0': - resolution: {integrity: sha512-mLKGKYnbmp6ZNVZ26sC1ftDOIpKqiPjujJ+9avVDM06eQhL+O9r9nPFFjx+4RNfH7z+6r7T2LOu6nPdpRPaUWA==} + '@objectstack/core@17.7.0': + resolution: {integrity: sha512-2/NqNk41eNo0nPgBsClefme2HwtLhwCdxKZER+XTOD345KAb4L0suyu2vGxHAN82MGkfNu4ticZzrRAHDT7tYQ==} engines: {node: '>=22.0.0'} - '@objectstack/driver-memory@17.6.0': - resolution: {integrity: sha512-kFsTtf/z0fq6NnwZLTGyRe5TxqJNJERZ+U6vjsseT8Pz0e1ucAPZRod+uFuyER2uAzm9xBpezJEr9UtoXmiB2A==} + '@objectstack/driver-memory@17.7.0': + resolution: {integrity: sha512-AkSMFi+CJeNxEvLhSVc2I9H9KUHEZgNC6ESxJE36SWxYjD6EsbFoHEjWUvUoiOVr0ETOJIvgjySIms3Ix2vaLQ==} engines: {node: '>=22.0.0'} - '@objectstack/driver-mongodb@17.6.0': - resolution: {integrity: sha512-jHg0mPdiox/uF3Xu2GoK2uUirhsKWTkwT5lvY1U2X+4qoA0r9JPevaesH1vM4uZ6l4DTlNzuLILB71WPm3zvrQ==} + '@objectstack/driver-mongodb@17.7.0': + resolution: {integrity: sha512-6iBxiXol0Bb93P1X7DM60e1Br7omycl65aSVUWr+3g9rr9tw+MYOK0R+SwmKfszW6TrWJxw6NN0OmNbl8/g+3Q==} engines: {node: '>=22.0.0'} - '@objectstack/driver-sql@17.6.0': - resolution: {integrity: sha512-1Px8TRjKB1sioE0QCamT/9pK11lOmExyoBvY20X64elt8RJpbOVcnm0q3X+qoRTQlPQrSNVbEshKhfKb7idLlg==} + '@objectstack/driver-sql@17.7.0': + resolution: {integrity: sha512-4gYyyvW5UFPzc0im+Q49EVLAK1HS8voAex69Pvlm/TIFXFKzSVmKwGy9xVYgFxISkHBjoCcdji+WRYSab0hIig==} engines: {node: '>=22.0.0'} peerDependencies: mysql2: ^3.0.0 @@ -622,23 +618,23 @@ packages: tedious: optional: true - '@objectstack/driver-sqlite-wasm@17.6.0': - resolution: {integrity: sha512-q7vZyDOwRbG2S9NNfUQ9kfG0Eah0KfKVchedBUOjL2VEp2banEzRPzHNMp3bSXdYu9nfmhaxFLflb2GdcmMSBw==} + '@objectstack/driver-sqlite-wasm@17.7.0': + resolution: {integrity: sha512-47ZZRIjCvLYOVOlSPsqyN+fLmKqnR5EoB0Xq5us+xZb2x+Qp32AjDRB+goz+HbJy69YmLq217hWCqmbLYfFH7w==} engines: {node: '>=22.0.0'} - '@objectstack/formula@17.6.0': - resolution: {integrity: sha512-5RpDNHLYJxqaivpDtM+QpltC5WlLRzwm58G9Y1us+6waZNnrV61eCDwV8JvaCsluneugcCVxp7oSDfjM8xZjAA==} + '@objectstack/formula@17.7.0': + resolution: {integrity: sha512-jf7SA/8QawVEKmQhwxjtyGxz+DIX+3V7M/Kt3z79jMhby5tjh5vwTbJI3PdyWCKQ1pS0epO6sSK7MddwLbEJ9Q==} - '@objectstack/lint@17.6.0': - resolution: {integrity: sha512-72LncQPEk1BnO3HWdtp+3Q9tik2lntQ8/WNfxtB5jqPo/9XQqDLjYaxCXmN1+mLtEkjk1ph/g8mHaSGORq9/4g==} + '@objectstack/lint@17.7.0': + resolution: {integrity: sha512-ddCHHRJKRSEirb74UNWd8DwdpqvQtMzsKH/bBiUslwXlYucQJPlQMd+ZVYN4V0IJoeD+IpD5el3P6S5H/wqPuQ==} engines: {node: '>=22.0.0'} - '@objectstack/mcp@17.6.0': - resolution: {integrity: sha512-8CjGmc15BaezyvLGP9tYHTvwpO3Z3wgZl4r1j93xbpSjl0H1/CZIl3zZg8RRjwQK6LUrQPVmBgkKbGh+JUUMeg==} + '@objectstack/mcp@17.7.0': + resolution: {integrity: sha512-WfAFbOjECCbXPUcEciSHd35P87Eagxzkz9gQm6YwbdIz7dvOJxikaqvQpG/Vq64rDG6K7u9nvL/BSYklbH9BEQ==} engines: {node: '>=22.0.0'} - '@objectstack/metadata-core@17.6.0': - resolution: {integrity: sha512-IgOxKA3IQKBGi6sAtdMtao2/TLEEMdFdJ42kixG9CHWEmuEx8nM/+2Mi9zsSt2wb1OKNJJw6Duy5iAHNPUoi5A==} + '@objectstack/metadata-core@17.7.0': + resolution: {integrity: sha512-dMDA0wZ0x6HBy+A9C4CjriK/NnUPKybSY/e/kPa7XUxe7mpoqfJlgwCC7RJs2HuHlKVJHL4VOn4NBcYaYzkwQg==} engines: {node: '>=22.0.0'} peerDependencies: vitest: ^4.0.0 @@ -646,98 +642,98 @@ packages: vitest: optional: true - '@objectstack/metadata-fs@17.6.0': - resolution: {integrity: sha512-pmnUJJf8S0kThVOyDPXdrigvFhmonKZL1GLWymyJTJ5Qa5IZfw518tdyJ2kTOJsJoeaaHZvy0YhrXFeTQkXSFg==} + '@objectstack/metadata-fs@17.7.0': + resolution: {integrity: sha512-jTn/xEGy8R9RbTnNalKxymHubjvloglYneRcFa/1I1/JuUllWgJsgogMHK2hG/pHwVOj1dN/WxgvmxTyMi36Lw==} engines: {node: '>=22.0.0'} - '@objectstack/metadata-protocol@17.6.0': - resolution: {integrity: sha512-UAPf5xrmytko0XhaGvvwn/LgSEZtLE+MqVRAM5aSuiS7rBEmy1/vUrANTHYEoi2WIXSKWOCItKc5wN+a2fcfiw==} + '@objectstack/metadata-protocol@17.7.0': + resolution: {integrity: sha512-fQIviSz1DxMeq8+2Tg83pU6EcSVkoQKagsB9XdepJPmDtPzdiPSgZMidLwTuVSQziVBy8RcOKGAuMEW2g4XF+g==} engines: {node: '>=22.0.0'} - '@objectstack/metadata@17.6.0': - resolution: {integrity: sha512-ZmA6vSSeUj44i/kr7xKhj740bjvh7aRXkhwszI1FvCxFSjnf2Nis3AFHsjibxzRYfRChyZTrh+rrBgwWBbZx5Q==} + '@objectstack/metadata@17.7.0': + resolution: {integrity: sha512-mkdXagkRy/ZpJiH15JOvYy/07vz1tLHdGIxv6EmWt8aeAYQyqoVsGdoLi1TY8MmI4tkG0w9qAWt2Myv9JPbZWQ==} engines: {node: '>=22.0.0'} - '@objectstack/objectql@17.6.0': - resolution: {integrity: sha512-CpNKUYkSmYJAhiqUr96zP3OJaUfABNRF67k22jYKN8Pfq9fD2RWT+Kv/iJyYY5Gs1V1uocA22dyBNXmRzo3+pg==} + '@objectstack/objectql@17.7.0': + resolution: {integrity: sha512-3TZlfQ1PUdC7+vPzipYHHgEAVIZlpHOB/vchkqoJaLDCuJ+nSfh1YwLfA6NN+Z3MxvNZfmZ1RWtMXsClX0nkeg==} engines: {node: '>=22.0.0'} - '@objectstack/observability@17.6.0': - resolution: {integrity: sha512-uGPR0M0L+HGIPAy28LyuWssQUQ2FY7BX5DSow0yDcO/E3rlzSMI248DfL3H//2u7g0QnfW4wkRXQXq4qDXyANg==} + '@objectstack/observability@17.7.0': + resolution: {integrity: sha512-7B5WhLcrW9iekKDikFwnMYxF4b2A8GKH/VxLTDVxaf1JMzzHXxxoq/9+MothmvDZpNWs1l6RuzhumjScKp82cw==} engines: {node: '>=22.0.0'} - '@objectstack/platform-objects@17.6.0': - resolution: {integrity: sha512-owxUrKQvBHohD9pUWlqjalU/XfGdXVYmoh08srMhZwT9y3AeobHcFYdpCU25Suf/M8HxxaOmVy/5Oe0pvbwRfg==} + '@objectstack/platform-objects@17.7.0': + resolution: {integrity: sha512-nYn2NRBj0TWhmdPMIRnWHunaoSKVyzJwzj2eRFcuV0+lEWkF6dTzJp6rTCMUelJ1qNqUKrTyN/8oD+JIaBke/g==} engines: {node: '>=22.0.0'} - '@objectstack/plugin-approvals@17.6.0': - resolution: {integrity: sha512-xiNWmPNWNZE/AqGhyp0/l7WOMhf/K3kwHPVED459sE3HimU1xVXgEuH0SZ3LDOtq+HYuyua65LxowFZw2YqvfQ==} + '@objectstack/plugin-approvals@17.7.0': + resolution: {integrity: sha512-je8T0dTSoTjqE1J140evxfzsvMiSpLoP3DEdu4NDFFJEWJDw/A/rBVHyQbVV0tLpW5j1pysze1myvF2Sc+MXlw==} - '@objectstack/plugin-audit@17.6.0': - resolution: {integrity: sha512-i55erLqrTDaSbiPIjT2es6kbMmbjjbAa16g/DNSGr36EhQybJnVBHN/CGGeaVwmUbszSYZuFCtPg/kpju4UUFg==} + '@objectstack/plugin-audit@17.7.0': + resolution: {integrity: sha512-Z0Wpx4W7oVPUwelmAXUckpABP0m+X9NwborOF/JDEmLOEQdi+2GCaWo2vazMJIx5ItyYLR7RYTvglwHa+ZSLQQ==} engines: {node: '>=22.0.0'} - '@objectstack/plugin-auth@17.6.0': - resolution: {integrity: sha512-FcaadfOKi29G3GjvvNGZlK9pHkbYk6dWtNol7V+KteFvv8RkzNllWJ+THeh1eivDLu7adoMPYWlPlreelhNcQA==} + '@objectstack/plugin-auth@17.7.0': + resolution: {integrity: sha512-JUOgGB6Riizw5QEZ5TXutRT1+PpaM/XpXMbtubAjk9dBGiR8NcfVoLoEFNz+Z5O6x82tdD8bcbt7GMDgUZ5wXA==} engines: {node: '>=22.0.0'} - '@objectstack/plugin-email@17.6.0': - resolution: {integrity: sha512-ULWu6IGScEmd68swCwBdybYRXtJlxAL8xERbLHOzUokdipmrScvkPPUkizvYFT94WooSbaqqizyvjCeVZHFxbg==} + '@objectstack/plugin-email@17.7.0': + resolution: {integrity: sha512-58vsGtSv0z6u+W3HqvESIW4OGxbB1/GpR1kY+PdlR0c6JfDc+/YuR0afWm6xrApBoaBPHoMWhtRyoyubgHTJeg==} - '@objectstack/plugin-hono-server@17.6.0': - resolution: {integrity: sha512-ue0J+NSrICU1pYxJnFwuYNGQQyJrHUUzkHSlNqldpDrNdU4n9AHg9omoipP4GKzQOlD0wVbg0zV3SyqhIsg0YA==} + '@objectstack/plugin-hono-server@17.7.0': + resolution: {integrity: sha512-VunIMCOQjdJE0J9dq4ebXGnUaLcOttvBNdWM74+J+/W8BflmyuHP/o3JkGo6wgP4e8WwwyTQjJ3BxNi4KrjlKA==} engines: {node: '>=22.0.0'} - '@objectstack/plugin-pinyin-search@17.6.0': - resolution: {integrity: sha512-fyWzunQ3k+ADjqYrw4YFfsfpyAf6J1aByNLEj6oxO050r/z6xGZfetuGkulnZOSoxQCHHyb5eOQk2cubnDI2EQ==} + '@objectstack/plugin-pinyin-search@17.7.0': + resolution: {integrity: sha512-2HYOdHNlUULzVS00ENv0EVrCA2yA4AWo3oHlCCJV1NHIqOJwimoIPzSu/FpBa+Z0y9T7cX4VxA4hYQO+/Giy8w==} - '@objectstack/plugin-security@17.6.0': - resolution: {integrity: sha512-82Xe6gRpeIUbrtGKkYoXny94y/dFObS5v2ZLLIqXmO3sIogeyZy41ZplQ5zlSXtmcAudwaE+lziE4jvDdSsWcA==} + '@objectstack/plugin-security@17.7.0': + resolution: {integrity: sha512-VlUT30iqnD39rAktDCqyAwJbtJTeWkJsFSZ+TFLE9pxcDIJqrCYQJuazn65QcyeQ+xdtkvnkzyPe3JsUz8i4sA==} engines: {node: '>=22.0.0'} - '@objectstack/plugin-sharing@17.6.0': - resolution: {integrity: sha512-KnwlGc9q3matd0gJqVbT5KgqKbYBep/F1H2c9Xboq6JBS97xIyEa/VkvqvdUABu/mTI02/9nad0s4JMI1TNhdw==} + '@objectstack/plugin-sharing@17.7.0': + resolution: {integrity: sha512-oAfwXmP2kQ6mBepPxYxsS6PUmi+XY15LX6kVgVJIwOGT/7iwsY6C4uejWNN7ZwFZ6j3970O43Ia/a73iY3gdbA==} - '@objectstack/plugin-webhooks@17.6.0': - resolution: {integrity: sha512-nCsQWW8zYcOL8akp5gWBMx5I8pOUeER6NmzvYPDTYkDvt8SZvHxgbYjUMoprmGal8agyEni5GqbYEu48C4ZM8A==} + '@objectstack/plugin-webhooks@17.7.0': + resolution: {integrity: sha512-VxGfFzJldxl5hUn8c8mlE7mrWwNnQJu3M8WPe2F76i5Pp7Hel6Q+yoQU566aechFPQLDkgsJNbVQbwYGAJr/DA==} - '@objectstack/rest@17.6.0': - resolution: {integrity: sha512-SIhVXmxpEnE9TH6jVp7o9GxvWF2GJoo5BsOzEiER7o7ezCOQef0fzgzaZklcmPxGJc1EuUz+ADQmbBvFg2zzDA==} + '@objectstack/rest@17.7.0': + resolution: {integrity: sha512-zCRPpyBAgdIAKEsgdfign2JmalkNCcCI98Kk6xlbnRg06E9NMIn4+D3Q1tsG7DsDtIY3Hao2vZlr6/59yhDy+w==} engines: {node: '>=22.0.0'} - '@objectstack/runtime@17.6.0': - resolution: {integrity: sha512-LvGNsF8BvlZdM3nztjuM/QIN7LyiiGBgL1IK6Oa0IpWQhIFjDuihu4jF5XJUIenas4WcP4H5jijWSmCOvbGF5w==} + '@objectstack/runtime@17.7.0': + resolution: {integrity: sha512-RVyleEk68NXBtdXCFtAarMEbP2JqoG+M9u8GwKERhgyKSfapXSOjfrcBXrAWJDNNXm9r5rrAH6P1Ap1rjUpoeA==} engines: {node: '>=22.0.0'} peerDependencies: - '@objectstack/driver-turso': ^17.6.0 + '@objectstack/driver-turso': ^17.7.0 peerDependenciesMeta: '@objectstack/driver-turso': optional: true - '@objectstack/sdui-parser@17.6.0': - resolution: {integrity: sha512-mMJxAXscqVTruSdRdzBfC1EufAXfX2jNDuyo1k0XNLkClLdJAgjmQBZtyMARUSEbGg33PC30gPx9IiBt7qYSFA==} + '@objectstack/sdui-parser@17.7.0': + resolution: {integrity: sha512-BaEt37YGK2lBgBXrM+w/tVI+kz5Gz6xhbmCDwgdeGCj8qKALNO8l/oQh/3qdsf6pLIBMfIi+IMqryOICgqwUdw==} - '@objectstack/service-analytics@17.6.0': - resolution: {integrity: sha512-wzvtvLutgeKZlKE/WZza9/2OBmKnW4GUS75NH6+cufAATuCNmC3+DyRjeEGa/BTgXQcLhdU9jzMV7h48QSPBcw==} + '@objectstack/service-analytics@17.7.0': + resolution: {integrity: sha512-EyVxpQykWckb9vPrxwpSDV9zpWCh5KmqVMPnXflZ0OO9ux4p9dwCFUoFvOzzYW7o3DjVmul7yxKCTY49A9b09w==} engines: {node: '>=22.0.0'} - '@objectstack/service-automation@17.6.0': - resolution: {integrity: sha512-SHF9fw0E/XTRC77NE9y6QT5v3au4mCL+pmw5Ji2fYkdmXszco4PPaVMc6Niyx1j7ZdxSNgX6iSI6s19KxGS5GQ==} + '@objectstack/service-automation@17.7.0': + resolution: {integrity: sha512-AZ1Ob0RrAe+kzjHJcLFUf393EQdgcmrHvW3q1MHU7FcF65CJsDs+9jcI40EE7vPz9kcqw/S/pUNkj+EwrLOfew==} engines: {node: '>=22.0.0'} - '@objectstack/service-cache@17.6.0': - resolution: {integrity: sha512-QIrVDq1T4gOvhEkpiq2XYtwQ+2+1Pb8R59gk5slI82G/Dle2M6Tlg9qkr+XZbnbIeLny4psVNjxgDW7US4YBEw==} + '@objectstack/service-cache@17.7.0': + resolution: {integrity: sha512-VP5MJQahN0tdkMuhKL/kfOa/czpZIUJK6n5V5Bmehg4ZEpYzIrzEP3oN0xSUDd8f3KTzHCSz6flKoD2Dtb48rA==} engines: {node: '>=22.0.0'} - '@objectstack/service-cluster@17.6.0': - resolution: {integrity: sha512-ngAf4WcBjxijIqFY+QKNCvqkKpQBcKCcbWiGqyOmQXmu/xXlETaQCUibK+Z/8FaZHVefy2J++wkGrhYluOYRrg==} + '@objectstack/service-cluster@17.7.0': + resolution: {integrity: sha512-btbcHBv9rPX3dB2Y0LqwsCsFCOiyqA8TmdTuv0CtLD/oc92l7JsIfPVP537w5E9i2H3UQ5wm1Epq7k9jCUlf+Q==} - '@objectstack/service-datasource@17.6.0': - resolution: {integrity: sha512-/0Jdp9yfAO5NQ/wcDGmPAERUYrQZKAkBj4D74kS7/B3spMDbyDKsnWvyUZuKZ0Mz4FnBCFTHAahppVLZ5M52Cg==} + '@objectstack/service-datasource@17.7.0': + resolution: {integrity: sha512-SOGSLaKFjXt7N7BPU2H5VAFkuEZ8bt9vvdbkaNDbj9x04oKkdFcaxn8QNluAwwI00W/5quutvim9symwnaIB7g==} peerDependencies: - '@objectstack/driver-mongodb': ^17.6.0 - '@objectstack/driver-sqlite-wasm': ^17.6.0 - '@objectstack/driver-turso': ^17.6.0 + '@objectstack/driver-mongodb': ^17.7.0 + '@objectstack/driver-sqlite-wasm': ^17.7.0 + '@objectstack/driver-turso': ^17.7.0 peerDependenciesMeta: '@objectstack/driver-mongodb': optional: true @@ -746,39 +742,39 @@ packages: '@objectstack/driver-turso': optional: true - '@objectstack/service-i18n@17.6.0': - resolution: {integrity: sha512-DzFLoxk/HMS78O8WE02hRc55SrKS65hEOcZ9TwlGbfojJ3jq/5B6i6j2HTB+hA9ZNB97my0wB/kcuQMGuK39xg==} + '@objectstack/service-i18n@17.7.0': + resolution: {integrity: sha512-A8RAETkXLh7qeni8YROBZbBU4h85i+D6YppUCBAw2MgTUSirTqYCVta/0MC1NTBd3NvZO0HlQk72BpSFzuNQ2g==} engines: {node: '>=22.0.0'} - '@objectstack/service-job@17.6.0': - resolution: {integrity: sha512-ggMuHC7baAF4ZrtoyTaMNvFQYhBe39oqPcsI19PjwT/yo8/+4rP6CCzKbaFTArYo9q15eTDCg5ACfXH17qm3HQ==} + '@objectstack/service-job@17.7.0': + resolution: {integrity: sha512-NcqnTI+5OrgkfOMtSKlNFcvQJqRxW4SLl7ttRn1HDeedwWnEjFQ8LvfMrGGkACgWHOyyLrnwm+t4QazhzPvWOg==} engines: {node: '>=22.0.0'} - '@objectstack/service-messaging@17.6.0': - resolution: {integrity: sha512-AAU+h4/Zzl+F0K0fmekBIeS7EPr9y8BSDbVhmtqSf2M22xELN23aupCXUXWHq+RqX25uTT1LoQ8TbPz1RgTXVA==} + '@objectstack/service-messaging@17.7.0': + resolution: {integrity: sha512-p66HSnoBXNeicnTT81dfT4tRsy5fjtSD1jcn+X3pRzEvQf56oFP/wn6eJHjcyjDvZP7zSe6joGIrQKxz6h6tjA==} engines: {node: '>=22.0.0'} - '@objectstack/service-package@17.6.0': - resolution: {integrity: sha512-w7nGWpDWCf5XNm2es35JF+X71f9jJ17ymUpovRECFYXKTBp5EshxWCdLM2DmQ3g4DijRkY+mMdrNMk0FowPoRA==} + '@objectstack/service-package@17.7.0': + resolution: {integrity: sha512-Jj3hYcs9+fG4bMGvoeKYrixOyY+ZKm92QowV2M9zsT921rUw4kyxgJgq6R+VfFmucEdy0KqTYVdK0jzP5dYiWw==} engines: {node: '>=22.0.0'} - '@objectstack/service-queue@17.6.0': - resolution: {integrity: sha512-V6mvM+jPELif0fhF+Y9jH2LwqHALfFO8hE9QV1xHG+uNkVImScz0JozhL31B+Pnd48um7Poy61XkSazyqyLCEQ==} + '@objectstack/service-queue@17.7.0': + resolution: {integrity: sha512-gqt0OZSTJha3XJMYwgSVS5Rfzb2pSRahSN4hc5UBpywXI0zpiFP9H9fzCpv++7eNmy2jSkjSIgIE+xy6FxlU6A==} engines: {node: '>=22.0.0'} - '@objectstack/service-realtime@17.6.0': - resolution: {integrity: sha512-BVsExuMhrGDPmcjvPWRQff1SlEFMbreMRgFOS5Rz5KekKIIz2ae9CLw4Vm+fERv606rLWvKiYHtjsNjKoPljLQ==} + '@objectstack/service-realtime@17.7.0': + resolution: {integrity: sha512-r+0UzUKvGGOxpDb9+dLoLh992uiM60d0q+KCiq/6E3pT/i8T3bfzTn3dSpYxZKQ3bxspXhP0FCaF8s30c0+FFQ==} engines: {node: '>=22.0.0'} - '@objectstack/service-settings@17.6.0': - resolution: {integrity: sha512-DCo4SvnY5mfmpa/QCuvwssKGZUZORY7dnb6vLiAzhfFawPe/tGg4TBm954onoLF1+stYGAgFRVwPgL+x5HreLA==} + '@objectstack/service-settings@17.7.0': + resolution: {integrity: sha512-qv/2OnV8Eq/h/GiUqACvt9UZLuV78zkjdZMPygpZhxTKlsLsA1o30XkdpEQUXTHGzMRW+wJkIkvHYhl/JT0yeA==} engines: {node: '>=22.0.0'} - '@objectstack/service-sms@17.6.0': - resolution: {integrity: sha512-eRI0dQTap7r4h3KP8aMSw10NC9JTdwtP5948Fh6kLnqfwmYErjzRwyQBrG6qfq/I7d/4ui5zDbvL/BoDaO9qfw==} + '@objectstack/service-sms@17.7.0': + resolution: {integrity: sha512-LDNB2iHEdiD0th90hzzkPOwaCKkin4zxo0tB5lrNwYJ9mEtkPFR7e7KqNMpCmCHLj6squcdrjQZDPQi9HIEfGg==} - '@objectstack/service-storage@17.6.0': - resolution: {integrity: sha512-uy018boDjdSkzOTkanBRp+fwgOXa3PLFls2F+wPJvv+rpUWAjTT8s0XTecHLBCg46KEti1MTHKZ8kqjngxE3KA==} + '@objectstack/service-storage@17.7.0': + resolution: {integrity: sha512-G4waSSMDtAq7+ChI0/39xSAUT1AbnN+XkrCZmtLuokcU7MUOA78GOVl1J2nzHiWrY+fOSggqSdVPfOy9oNom+g==} engines: {node: '>=22.0.0'} peerDependencies: '@aws-sdk/client-s3': ^3.0.0 @@ -789,12 +785,12 @@ packages: '@aws-sdk/s3-request-presigner': optional: true - '@objectstack/setup@17.6.0': - resolution: {integrity: sha512-nwSQ49IEHEIy2GpZHdL+m0m1FGll1BHH5X9+d1lsyJMYfRju7cunsP14rxtwMhWMoNSF+mE5hYugffMUfXdcTQ==} + '@objectstack/setup@17.7.0': + resolution: {integrity: sha512-8JwpJ0QjDHPpK/0en/hLVnqP4G52VWKg8gNauc2yI5NDr4xJjkkrmrn+q2FWnRB3fSHvzxZ138Sbj6lQj9ikWg==} engines: {node: '>=22.0.0'} - '@objectstack/spec@17.6.0': - resolution: {integrity: sha512-i5il5q0vIYjYrkHznsCXuO8C6Ftrs2RU4MxRHWrW3TsR7t/VUoe3sSfVLHDaudV+LfVVUDD9QHsWex1MCdckrA==} + '@objectstack/spec@17.7.0': + resolution: {integrity: sha512-PmKFK2C+NHiVoCAC+hYifJJWKiiJxZxN/FlpCQKwqPwajPxCcEUk0oVH0Af0yG3AFRQVCXxwIgEHGGeAa8Z4tA==} engines: {node: '>=22.0.0'} peerDependencies: ai: ^7.0.0 @@ -802,23 +798,23 @@ packages: ai: optional: true - '@objectstack/trigger-api@17.6.0': - resolution: {integrity: sha512-QM0ID3EVdeVcvqtEREDjY8LMo6n4WRevv4SsQCzPeQRa8aRqvy9LCj0ph2VMfXPZGlV0DWYS6N3Q+BIpwzPSOg==} + '@objectstack/trigger-api@17.7.0': + resolution: {integrity: sha512-YiTgJN9ewxfdL0Q1U/bQho1EDfPZpGAEIgzYAFli+keVRaQyKrH7BjKTxW5RKb4rwCplCFwkNO+AsRQHpJ1K3Q==} - '@objectstack/trigger-record-change@17.6.0': - resolution: {integrity: sha512-EFzciTYjyCP0cyLMAq7xBTwJS4naoGEX3CMobwitLEOeHi+XIjzCaqT+oB2pyzl9CmlHaqe5rejGLfnxz6Ft8g==} + '@objectstack/trigger-record-change@17.7.0': + resolution: {integrity: sha512-H7zpibqfOpk8PsmBpKPSkVdyAM/JzxUUakYGY5/Wpg1pMFFx0g0cCREFYcHWCyv2s8YGmwN52gkEsc1QaoaCYw==} engines: {node: '>=22.0.0'} - '@objectstack/trigger-schedule@17.6.0': - resolution: {integrity: sha512-7ai2PgxVNk1ADPbZ1e5Mz+sPHT8Akdff7bA/qU85IYG6/u2EgkzAWR6qudh3K6P7rSd9kvUoVyZkSClaSXYBBA==} + '@objectstack/trigger-schedule@17.7.0': + resolution: {integrity: sha512-eMZgTyXRQk9vrG3p5aY68xW+QN0G+59unsGHwzCzWig7jleOZQlPf48E6WrXAbTEWKYM36bXmC6CU/44bIwG/g==} engines: {node: '>=22.0.0'} - '@objectstack/types@17.6.0': - resolution: {integrity: sha512-yH4B4YZt0cdSkenjifKY5o8svaV+PMPCdV0Tm0FMo3w1o6ShhF5gQK/PvU9lwFaRsEAB9SuJ70nCURfIAVoLsw==} + '@objectstack/types@17.7.0': + resolution: {integrity: sha512-7EIBYXZsZrBMihmmhwfcafI7F8WUvWNRAylJsZ25mBO7okQLhL4J3GX4wYBiyAJUmroIF3R9lCi+noaoWj5E5g==} engines: {node: '>=22.0.0'} - '@objectstack/verify@17.6.0': - resolution: {integrity: sha512-9jSRWIPXMgBE3dJtNZtrBE+x0PrWUwCUn7I1KYiutz/aXM1UDbv0z49NkOWcSwqRuAJJrC+/aosqZJP5J/f9rA==} + '@objectstack/verify@17.7.0': + resolution: {integrity: sha512-2CG2DlPHSvS9E0Sr0/h3MGG20drHI9XwUomICyYZJU5cKlC97PWarIlzpDdUvkA3/LGARDxX7eZPaDyxsU81Ew==} engines: {node: '>=22.0.0'} '@oclif/core@5.1.2': @@ -1531,8 +1527,8 @@ packages: resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} engines: {node: '>= 10'} - create-objectstack@17.6.0: - resolution: {integrity: sha512-/aoG5+ImDULiSS/fi3XjgEGdmbad/bMifQf+8QiJgOaJ0YNr7iU0YkZXnxAXVDMZObr3hslc/ixW+UTrHozD9Q==} + create-objectstack@17.7.0: + resolution: {integrity: sha512-TLrwK23OcDR7K4JpR6FbBK+U5SfQhPyONNea0cgydfcfpjQaBYULmmuhDARvoTsUZGOSuVrVWxSETnKYg2lKvA==} engines: {node: '>=22.0.0'} hasBin: true @@ -2023,9 +2019,6 @@ packages: jose@6.2.12: resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==} - jose@6.2.9: - resolution: {integrity: sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==} - js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -3622,7 +3615,7 @@ snapshots: express: 5.2.1 express-rate-limit: 8.6.1(express@5.2.1) hono: 4.13.11 - jose: 6.2.9 + jose: 6.2.12 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 @@ -3642,77 +3635,75 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true - '@noble/ciphers@2.3.0': {} - '@noble/ciphers@2.4.0': {} '@noble/hashes@2.4.0': {} '@nodable/entities@3.0.0': {} - '@objectstack/account@17.6.0(vitest@4.1.10)': + '@objectstack/account@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/cli@17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': - dependencies: - '@objectstack/account': 17.6.0(vitest@4.1.10) - '@objectstack/client': 17.6.0 - '@objectstack/cloud-connection': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/console': 17.6.0 - '@objectstack/core': 17.6.0 - '@objectstack/driver-memory': 17.6.0 - '@objectstack/driver-mongodb': 17.6.0 - '@objectstack/driver-sql': 17.6.0 - '@objectstack/driver-sqlite-wasm': 17.6.0(better-sqlite3@13.0.3) - '@objectstack/formula': 17.6.0 - '@objectstack/lint': 17.6.0 - '@objectstack/mcp': 17.6.0 - '@objectstack/metadata': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-protocol': 17.6.0(vitest@4.1.10) - '@objectstack/objectql': 17.6.0(vitest@4.1.10) - '@objectstack/observability': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-approvals': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-audit': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-auth': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/plugin-email': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-hono-server': 17.6.0 - '@objectstack/plugin-pinyin-search': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-security': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-sharing': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-webhooks': 17.6.0(vitest@4.1.10) - '@objectstack/rest': 17.6.0(vitest@4.1.10) - '@objectstack/runtime': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/service-analytics': 17.6.0 - '@objectstack/service-automation': 17.6.0(vitest@4.1.10) - '@objectstack/service-cache': 17.6.0 - '@objectstack/service-datasource': 17.6.0(@objectstack/driver-mongodb@17.6.0)(@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3)) - '@objectstack/service-job': 17.6.0(vitest@4.1.10) - '@objectstack/service-messaging': 17.6.0(vitest@4.1.10) - '@objectstack/service-package': 17.6.0(vitest@4.1.10) - '@objectstack/service-queue': 17.6.0(vitest@4.1.10) - '@objectstack/service-realtime': 17.6.0(vitest@4.1.10) - '@objectstack/service-settings': 17.6.0(vitest@4.1.10) - '@objectstack/service-sms': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/service-storage': 17.6.0(vitest@4.1.10) - '@objectstack/setup': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/trigger-api': 17.6.0 - '@objectstack/trigger-record-change': 17.6.0 - '@objectstack/trigger-schedule': 17.6.0(vitest@4.1.10) - '@objectstack/types': 17.6.0 - '@objectstack/verify': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@objectstack/driver-mongodb@17.6.0)(@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3))(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/cli@17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': + dependencies: + '@objectstack/account': 17.7.0(vitest@4.1.10) + '@objectstack/client': 17.7.0 + '@objectstack/cloud-connection': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/console': 17.7.0 + '@objectstack/core': 17.7.0 + '@objectstack/driver-memory': 17.7.0 + '@objectstack/driver-mongodb': 17.7.0 + '@objectstack/driver-sql': 17.7.0 + '@objectstack/driver-sqlite-wasm': 17.7.0(better-sqlite3@13.0.3) + '@objectstack/formula': 17.7.0 + '@objectstack/lint': 17.7.0 + '@objectstack/mcp': 17.7.0 + '@objectstack/metadata': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-protocol': 17.7.0(vitest@4.1.10) + '@objectstack/objectql': 17.7.0(vitest@4.1.10) + '@objectstack/observability': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-approvals': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-audit': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-auth': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/plugin-email': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-hono-server': 17.7.0 + '@objectstack/plugin-pinyin-search': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-security': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-sharing': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-webhooks': 17.7.0(vitest@4.1.10) + '@objectstack/rest': 17.7.0(vitest@4.1.10) + '@objectstack/runtime': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/service-analytics': 17.7.0 + '@objectstack/service-automation': 17.7.0(vitest@4.1.10) + '@objectstack/service-cache': 17.7.0 + '@objectstack/service-datasource': 17.7.0(@objectstack/driver-mongodb@17.7.0)(@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3))(vitest@4.1.10) + '@objectstack/service-job': 17.7.0(vitest@4.1.10) + '@objectstack/service-messaging': 17.7.0(vitest@4.1.10) + '@objectstack/service-package': 17.7.0(vitest@4.1.10) + '@objectstack/service-queue': 17.7.0(vitest@4.1.10) + '@objectstack/service-realtime': 17.7.0(vitest@4.1.10) + '@objectstack/service-settings': 17.7.0(vitest@4.1.10) + '@objectstack/service-sms': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/service-storage': 17.7.0(vitest@4.1.10) + '@objectstack/setup': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/trigger-api': 17.7.0 + '@objectstack/trigger-record-change': 17.7.0 + '@objectstack/trigger-schedule': 17.7.0(vitest@4.1.10) + '@objectstack/types': 17.7.0 + '@objectstack/verify': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@objectstack/driver-mongodb@17.7.0)(@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3))(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) '@oclif/core': 5.1.2 bundle-require: 5.1.0(esbuild@0.28.2) chalk: 6.0.1 chokidar: 5.0.0 - create-objectstack: 17.6.0 + create-objectstack: 17.7.0 dotenv-flow: 4.1.0 esbuild: 0.28.2 ts-morph: 28.0.0 @@ -3766,19 +3757,21 @@ snapshots: - vitest - vue - '@objectstack/client@17.6.0': + '@objectstack/client@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/cloud-connection@17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': + '@objectstack/cloud-connection@17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/runtime': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-protocol': 17.7.0(vitest@4.1.10) + '@objectstack/runtime': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@better-auth/utils' @@ -3823,30 +3816,30 @@ snapshots: - vitest - vue - '@objectstack/console@17.6.0': {} + '@objectstack/console@17.7.0': {} - '@objectstack/core@17.6.0': + '@objectstack/core@17.7.0': dependencies: - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 zod: 4.6.5 transitivePeerDependencies: - ai - '@objectstack/driver-memory@17.6.0': + '@objectstack/driver-memory@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 mingo: 7.2.4 transitivePeerDependencies: - ai - '@objectstack/driver-mongodb@17.6.0': + '@objectstack/driver-mongodb@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 mongodb: 7.7.0 nanoid: 6.0.1 transitivePeerDependencies: @@ -3859,12 +3852,12 @@ snapshots: - snappy - socks - '@objectstack/driver-sql@17.6.0': + '@objectstack/driver-sql@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/observability': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/observability': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 knex: 3.3.0(better-sqlite3@13.0.3) nanoid: 6.0.1 optionalDependencies: @@ -3878,11 +3871,11 @@ snapshots: - sqlite3 - supports-color - '@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3)': + '@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/driver-sql': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/driver-sql': 17.7.0 + '@objectstack/spec': 17.7.0 knex: 3.3.0(better-sqlite3@13.0.3) nanoid: 6.0.1 sql.js: 1.14.2 @@ -3899,18 +3892,18 @@ snapshots: - supports-color - tedious - '@objectstack/formula@17.6.0': + '@objectstack/formula@17.7.0': dependencies: '@marcbachmann/cel-js': 8.0.0 - '@objectstack/spec': 17.6.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/lint@17.6.0': + '@objectstack/lint@17.7.0': dependencies: - '@objectstack/formula': 17.6.0 - '@objectstack/sdui-parser': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/formula': 17.7.0 + '@objectstack/sdui-parser': 17.7.0 + '@objectstack/spec': 17.7.0 ajv: 8.20.0 ajv-formats: 3.0.1 sucrase: 3.35.1 @@ -3918,58 +3911,58 @@ snapshots: transitivePeerDependencies: - ai - '@objectstack/mcp@17.6.0': + '@objectstack/mcp@17.7.0': dependencies: '@modelcontextprotocol/sdk': 1.31.0(zod@4.6.5) - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 zod: 4.6.5 transitivePeerDependencies: - '@cfworker/json-schema' - ai - supports-color - '@objectstack/metadata-core@17.6.0(vitest@4.1.10)': + '@objectstack/metadata-core@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/spec': 17.6.0 + '@objectstack/spec': 17.7.0 zod: 4.6.5 optionalDependencies: vitest: 4.1.10(@vitest/coverage-v8@4.1.10)(esbuild@0.28.2)(tsx@4.23.15)(yaml@2.9.1) transitivePeerDependencies: - ai - '@objectstack/metadata-fs@17.6.0(vitest@4.1.10)': + '@objectstack/metadata-fs@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) chokidar: 5.0.0 transitivePeerDependencies: - ai - vitest - '@objectstack/metadata-protocol@17.6.0(vitest@4.1.10)': + '@objectstack/metadata-protocol@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/lint': 17.6.0 - '@objectstack/metadata': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/sdui-parser': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/lint': 17.7.0 + '@objectstack/metadata': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/sdui-parser': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 zod: 4.6.5 transitivePeerDependencies: - ai - vitest - '@objectstack/metadata@17.6.0(vitest@4.1.10)': + '@objectstack/metadata@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-fs': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-fs': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 chokidar: 5.0.0 glob: 13.0.6 js-yaml: 5.4.2 @@ -3978,15 +3971,15 @@ snapshots: - ai - vitest - '@objectstack/objectql@17.6.0(vitest@4.1.10)': + '@objectstack/objectql@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/metadata': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-protocol': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/metadata': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-protocol': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 ajv: 8.20.0 ajv-formats: 3.0.1 zod: 4.6.5 @@ -3994,57 +3987,57 @@ snapshots: - ai - vitest - '@objectstack/observability@17.6.0': + '@objectstack/observability@17.7.0': dependencies: - '@objectstack/spec': 17.6.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/platform-objects@17.6.0(vitest@4.1.10)': + '@objectstack/platform-objects@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-approvals@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-approvals@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-audit@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-audit@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/objectql': 17.6.0(vitest@4.1.10) - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/objectql': 17.7.0(vitest@4.1.10) + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-auth@17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': + '@objectstack/plugin-auth@17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': dependencies: '@better-auth/core': 1.7.3(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.4)(nanostores@1.4.2) '@better-auth/oauth-provider': 1.7.3(@better-auth/core@1.7.3(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.4)(nanostores@1.4.2))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.7.3(better-sqlite3@13.0.3)(mongodb@7.7.0)(vitest@4.1.10))(better-call@1.4.0(zod@4.6.5)) '@better-auth/scim': 1.7.3(@better-auth/core@1.7.3(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.4)(nanostores@1.4.2))(@better-auth/utils@0.4.2)(better-auth@1.7.3(better-sqlite3@13.0.3)(mongodb@7.7.0)(vitest@4.1.10))(better-call@1.4.0(zod@4.6.5)) '@better-auth/sso': 1.7.3(@better-auth/core@1.7.3(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.4)(nanostores@1.4.2))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.7.3(better-sqlite3@13.0.3)(mongodb@7.7.0)(vitest@4.1.10))(better-call@1.4.0(zod@4.6.5)) '@noble/hashes': 2.4.0 - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/rest': 17.6.0(vitest@4.1.10) - '@objectstack/service-messaging': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/rest': 17.7.0(vitest@4.1.10) + '@objectstack/service-messaging': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 better-auth: 1.7.3(better-sqlite3@13.0.3)(mongodb@7.7.0)(vitest@4.1.10) jose: 6.2.12 transitivePeerDependencies: @@ -4076,112 +4069,113 @@ snapshots: - vitest - vue - '@objectstack/plugin-email@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-email@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 nodemailer: 10.0.12 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-hono-server@17.6.0': + '@objectstack/plugin-hono-server@17.7.0': dependencies: '@hono/node-server': 2.1.1(hono@4.13.11) - '@objectstack/core': 17.6.0 - '@objectstack/observability': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/observability': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 hono: 4.13.11 transitivePeerDependencies: - ai - '@objectstack/plugin-pinyin-search@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-pinyin-search@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/objectql': 17.6.0(vitest@4.1.10) - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/objectql': 17.7.0(vitest@4.1.10) + '@objectstack/types': 17.7.0 pinyin-pro: 3.29.4 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-security@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-security@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-sharing@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-sharing@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/objectql': 17.6.0(vitest@4.1.10) - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@noble/hashes': 2.4.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/objectql': 17.7.0(vitest@4.1.10) + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/plugin-webhooks@17.6.0(vitest@4.1.10)': + '@objectstack/plugin-webhooks@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/service-messaging': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/service-messaging': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/rest@17.6.0(vitest@4.1.10)': + '@objectstack/rest@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/observability': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/service-package': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/observability': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/service-package': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 exceljs: 4.4.0 zod: 4.6.5 transitivePeerDependencies: - ai - vitest - '@objectstack/runtime@17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': - dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/driver-memory': 17.6.0 - '@objectstack/driver-sql': 17.6.0 - '@objectstack/driver-sqlite-wasm': 17.6.0(better-sqlite3@13.0.3) - '@objectstack/formula': 17.6.0 - '@objectstack/metadata': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/metadata-protocol': 17.6.0(vitest@4.1.10) - '@objectstack/objectql': 17.6.0(vitest@4.1.10) - '@objectstack/observability': 17.6.0 - '@objectstack/plugin-auth': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/plugin-security': 17.6.0(vitest@4.1.10) - '@objectstack/rest': 17.6.0(vitest@4.1.10) - '@objectstack/service-cluster': 17.6.0 - '@objectstack/service-datasource': 17.6.0(@objectstack/driver-mongodb@17.6.0)(@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3)) - '@objectstack/service-i18n': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/runtime@17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': + dependencies: + '@objectstack/core': 17.7.0 + '@objectstack/driver-memory': 17.7.0 + '@objectstack/driver-sql': 17.7.0 + '@objectstack/driver-sqlite-wasm': 17.7.0(better-sqlite3@13.0.3) + '@objectstack/formula': 17.7.0 + '@objectstack/metadata': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-protocol': 17.7.0(vitest@4.1.10) + '@objectstack/objectql': 17.7.0(vitest@4.1.10) + '@objectstack/observability': 17.7.0 + '@objectstack/plugin-auth': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/plugin-security': 17.7.0(vitest@4.1.10) + '@objectstack/rest': 17.7.0(vitest@4.1.10) + '@objectstack/service-cluster': 17.7.0 + '@objectstack/service-datasource': 17.7.0(@objectstack/driver-mongodb@17.7.0)(@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3))(vitest@4.1.10) + '@objectstack/service-i18n': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 quickjs-emscripten: 0.32.0 zod: 4.6.5 optionalDependencies: - '@objectstack/driver-mongodb': 17.6.0 + '@objectstack/driver-mongodb': 17.7.0 transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@better-auth/utils' @@ -4225,54 +4219,56 @@ snapshots: - vitest - vue - '@objectstack/sdui-parser@17.6.0': {} + '@objectstack/sdui-parser@17.7.0': {} - '@objectstack/service-analytics@17.6.0': + '@objectstack/service-analytics@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/service-automation@17.6.0(vitest@4.1.10)': + '@objectstack/service-automation@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/formula': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/formula': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/metadata-protocol': 17.7.0(vitest@4.1.10) + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/service-cache@17.6.0': + '@objectstack/service-cache@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/observability': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/observability': 17.7.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/service-cluster@17.6.0': + '@objectstack/service-cluster@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/service-datasource@17.6.0(@objectstack/driver-mongodb@17.6.0)(@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3))': + '@objectstack/service-datasource@17.7.0(@objectstack/driver-mongodb@17.7.0)(@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3))(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/driver-memory': 17.6.0 - '@objectstack/driver-sql': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/driver-memory': 17.7.0 + '@objectstack/driver-sql': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 pg-connection-string: 2.14.0 optionalDependencies: - '@objectstack/driver-mongodb': 17.6.0 - '@objectstack/driver-sqlite-wasm': 17.6.0(better-sqlite3@13.0.3) + '@objectstack/driver-mongodb': 17.7.0 + '@objectstack/driver-sqlite-wasm': 17.7.0(better-sqlite3@13.0.3) transitivePeerDependencies: - ai - mariadb @@ -4284,78 +4280,79 @@ snapshots: - sqlite3 - supports-color - tedious + - vitest - '@objectstack/service-i18n@17.6.0': + '@objectstack/service-i18n@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/service-job@17.6.0(vitest@4.1.10)': + '@objectstack/service-job@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 croner: 10.0.1 transitivePeerDependencies: - ai - vitest - '@objectstack/service-messaging@17.6.0(vitest@4.1.10)': + '@objectstack/service-messaging@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/service-package@17.6.0(vitest@4.1.10)': + '@objectstack/service-package@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/service-queue@17.6.0(vitest@4.1.10)': + '@objectstack/service-queue@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/service-realtime@17.6.0(vitest@4.1.10)': + '@objectstack/service-realtime@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/service-settings@17.6.0(vitest@4.1.10)': + '@objectstack/service-settings@17.7.0(vitest@4.1.10)': dependencies: '@noble/ciphers': 2.4.0 - '@objectstack/core': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/service-sms@17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': + '@objectstack/service-sms@17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/plugin-auth': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/plugin-auth': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - '@better-auth/utils' - '@better-fetch/fetch' @@ -4385,78 +4382,78 @@ snapshots: - vitest - vue - '@objectstack/service-storage@17.6.0(vitest@4.1.10)': + '@objectstack/service-storage@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/observability': 17.6.0 - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/observability': 17.7.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/setup@17.6.0(vitest@4.1.10)': + '@objectstack/setup@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - vitest - '@objectstack/spec@17.6.0': + '@objectstack/spec@17.7.0': dependencies: pg-connection-string: 2.14.0 zod: 4.6.5 - '@objectstack/trigger-api@17.6.0': + '@objectstack/trigger-api@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/trigger-record-change@17.6.0': + '@objectstack/trigger-record-change@17.7.0': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/spec': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/trigger-schedule@17.6.0(vitest@4.1.10)': + '@objectstack/trigger-schedule@17.7.0(vitest@4.1.10)': dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/metadata-core': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/core': 17.7.0 + '@objectstack/metadata-core': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 croner: 10.0.1 transitivePeerDependencies: - ai - vitest - '@objectstack/types@17.6.0': + '@objectstack/types@17.7.0': dependencies: - '@objectstack/spec': 17.6.0 + '@objectstack/spec': 17.7.0 transitivePeerDependencies: - ai - '@objectstack/verify@17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@objectstack/driver-mongodb@17.6.0)(@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3))(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': - dependencies: - '@objectstack/core': 17.6.0 - '@objectstack/objectql': 17.6.0(vitest@4.1.10) - '@objectstack/platform-objects': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-auth': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/plugin-hono-server': 17.6.0 - '@objectstack/plugin-security': 17.6.0(vitest@4.1.10) - '@objectstack/plugin-sharing': 17.6.0(vitest@4.1.10) - '@objectstack/rest': 17.6.0(vitest@4.1.10) - '@objectstack/runtime': 17.6.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) - '@objectstack/service-analytics': 17.6.0 - '@objectstack/service-automation': 17.6.0(vitest@4.1.10) - '@objectstack/service-datasource': 17.6.0(@objectstack/driver-mongodb@17.6.0)(@objectstack/driver-sqlite-wasm@17.6.0(better-sqlite3@13.0.3)) - '@objectstack/service-settings': 17.6.0(vitest@4.1.10) - '@objectstack/spec': 17.6.0 - '@objectstack/types': 17.6.0 + '@objectstack/verify@17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@objectstack/driver-mongodb@17.7.0)(@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3))(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10)': + dependencies: + '@objectstack/core': 17.7.0 + '@objectstack/objectql': 17.7.0(vitest@4.1.10) + '@objectstack/platform-objects': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-auth': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/plugin-hono-server': 17.7.0 + '@objectstack/plugin-security': 17.7.0(vitest@4.1.10) + '@objectstack/plugin-sharing': 17.7.0(vitest@4.1.10) + '@objectstack/rest': 17.7.0(vitest@4.1.10) + '@objectstack/runtime': 17.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(better-sqlite3@13.0.3)(kysely@0.29.4)(mongodb@7.7.0)(nanostores@1.4.2)(vitest@4.1.10) + '@objectstack/service-analytics': 17.7.0 + '@objectstack/service-automation': 17.7.0(vitest@4.1.10) + '@objectstack/service-datasource': 17.7.0(@objectstack/driver-mongodb@17.7.0)(@objectstack/driver-sqlite-wasm@17.7.0(better-sqlite3@13.0.3))(vitest@4.1.10) + '@objectstack/service-settings': 17.7.0(vitest@4.1.10) + '@objectstack/spec': 17.7.0 + '@objectstack/types': 17.7.0 transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@better-auth/utils' @@ -4909,7 +4906,7 @@ snapshots: '@better-auth/telemetry': 1.7.3(@better-auth/core@1.7.3(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.4)(nanostores@1.4.2))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.1 - '@noble/ciphers': 2.3.0 + '@noble/ciphers': 2.4.0 '@noble/hashes': 2.4.0 better-call: 1.4.0(zod@4.6.5) defu: 6.1.7 @@ -5096,7 +5093,7 @@ snapshots: crc-32: 1.2.2 readable-stream: 3.6.2 - create-objectstack@17.6.0: + create-objectstack@17.7.0: dependencies: chalk: 6.0.1 commander: 15.0.0 @@ -5608,8 +5605,6 @@ snapshots: jose@6.2.12: {} - jose@6.2.9: {} - js-tokens@10.0.0: {} js-yaml@5.4.2: diff --git a/scripts/backfill-contact-mailing-address.ts b/scripts/backfill-contact-mailing-address.ts index 10205433..54c14f5f 100644 --- a/scripts/backfill-contact-mailing-address.ts +++ b/scripts/backfill-contact-mailing-address.ts @@ -6,6 +6,12 @@ // pnpm exec tsx scripts/backfill-contact-mailing-address.ts --url https:// --email --password // pnpm exec tsx scripts/backfill-contact-mailing-address.ts ... --apply # without this it only reports // +// On @objectstack 17.7.0 and later, read the old columns with the platform's +// own command first, from the project root, and hand its output to this script: +// +// pnpm exec objectstack migrate unmapped-columns --object crm_contact --json > contact-unmapped.json +// pnpm exec tsx scripts/backfill-contact-mailing-address.ts ... --unmapped contact-unmapped.json [--apply] +// // ─── RUN THIS AFTER UPGRADING, AND BEFORE `os migrate apply --allow-destructive` ─── // // HotCRM used to store a contact's address as five text fields — @@ -16,13 +22,19 @@ // // Upgrading does not move the old values, and it does not delete them either: // the five columns stay in the database as ORPHANED columns (`os migrate plan` -// lists them as `unmapped_column`). An unprojected REST read still returns -// them — measured on @objectstack 17.6.0 with SQLite — and that is where this -// script reads from. `os migrate apply --allow-destructive` drops orphaned -// columns, and with them the only copy of the old addresses, so run this first. +// lists them as `unmapped_column`). `os migrate apply --allow-destructive` drops +// orphaned columns, and with them the only copy of the old addresses, so run +// this first. Where the old values are read from depends on the runtime: +// • @objectstack 17.7.0 and later serve declared fields only, so no REST read +// returns an orphaned column (measured: the unprojected read of a contact +// whose `mailing_street` column held a value carried no `mailing_*` key). +// The operator-only `os migrate unmapped-columns` reads them straight from +// the database instead; pass its JSON with `--unmapped FILE`. +// • Without `--unmapped`, the script reads the unprojected REST rows, which +// still carried the orphaned columns on 17.6.0 (measured with SQLite). // -// It talks to the REST API and nothing else — no imports from `src/`, no raw -// SQL — so the old column names are written out literally below. +// It writes through the REST API and nothing else — no imports from `src/`, no +// raw SQL — so the old column names are written out literally below. // // What it writes, per contact: // • the non-blank old columns become the matching parts of `mailing_address` @@ -39,6 +51,8 @@ // fields), so a value it cannot map stays where it is, and is listed; // • rerunnable: a second pass over a converted org reports zero rows to write. +import { readFileSync } from 'node:fs'; + type Json = Record; const DEFAULT_URL = 'http://localhost:4001'; @@ -66,6 +80,19 @@ function arg(name: string, envName: string, fallback: string): string { const APPLY = process.argv.slice(2).includes('--apply'); +/** + * The old values, keyed by contact id, from the JSON `os migrate + * unmapped-columns --object crm_contact --json` prints — `{ object, records: + * [{ id, values: { : } }] }`. Read from the file, never guessed. + */ +function readUnmapped(file: string): Map { + const doc = JSON.parse(readFileSync(file, 'utf8')) as Json; + if (doc?.object !== OBJECT || !Array.isArray(doc?.records)) { + throw new Error(`${file} is not \`os migrate unmapped-columns --object ${OBJECT} --json\` output`); + } + return new Map((doc.records as Json[]).map((r) => [String(r.id), (r.values ?? {}) as Json])); +} + class Api { private cookie = ''; constructor(private readonly base: URL) {} @@ -171,7 +198,20 @@ async function main(): Promise { console.log(`Signed in as ${me.email ?? me.id} at ${url}`); console.log(APPLY ? 'Mode: APPLY (records will be written)' : 'Mode: REPORT ONLY (pass --apply to write)'); - const rows = await api.allContacts(); + const unmappedFile = arg('unmapped', 'HOTCRM_UNMAPPED_FILE', ''); + const legacy = unmappedFile ? readUnmapped(unmappedFile) : undefined; + if (unmappedFile) console.log(`Old columns: ${legacy!.size} row(s) from ${unmappedFile}`); + + // With `--unmapped`, the old columns come from the file and everything else + // (the current `mailing_address`) from the REST row; a file row whose contact + // the API does not return is listed, never written. + const rest = await api.allContacts(); + const rows = legacy ? rest.map((r) => ({ ...r, ...(legacy.get(String(r.id)) ?? {}) })) : rest; + if (legacy) { + const seen = new Set(rest.map((r) => String(r.id))); + const missing = [...legacy.keys()].filter((id) => !seen.has(id)); + if (missing.length) console.log(` ${missing.length} id(s) in the file that the API does not return (skipped): ${missing.slice(0, 20).join(', ')}`); + } const legacyVisible = rows.some((r) => LEGACY_TO_PART.some(([column]) => column in r)); const todo: Todo[] = []; @@ -200,6 +240,10 @@ async function main(): Promise { console.log('read here. Either this org never had them (installed on this release or later), or'); console.log('they are gone — dropped by `os migrate apply --allow-destructive`, or not returned by'); console.log('this runtime. In the last two cases the old addresses cannot be recovered from the API.'); + if (!legacy) { + console.log('On @objectstack 17.7.0 or later no REST read returns an orphaned column: read them with'); + console.log(`\`objectstack migrate unmapped-columns --object ${OBJECT} --json > FILE\` and pass --unmapped FILE.`); + } return; } console.log(` ${noAddress} with no old address (left empty)`); diff --git a/src/marketing/flows/campaign-enrollment.flow.ts b/src/marketing/flows/campaign-enrollment.flow.ts index 24705e1c..429c129b 100644 --- a/src/marketing/flows/campaign-enrollment.flow.ts +++ b/src/marketing/flows/campaign-enrollment.flow.ts @@ -55,7 +55,7 @@ export const CampaignEnrollmentFlow: Flow = { * * ⚠️ Measured on the 17.1.0 spec, with the schema key re-checked on 17.2.0. * Neither that key nor the seeding behaviour was re-checked on 17.3.0 or - * 17.4.0 (PR #1814, #1807), nor on 17.5.0 or 17.6.0 (the pin since the 17.6.0 bump). + * 17.4.0 (PR #1814, #1807), nor on 17.5.0, 17.6.0 or 17.7.0 (the pin since the 17.7.0 bump). * * ⛔ Never seed this with an assignment node instead. An assignment is * unconditional, so it CLOBBERS a supplied param — measured: launching with diff --git a/src/sales/pages/lead_detail.page.ts b/src/sales/pages/lead_detail.page.ts index e45cd08b..813fca00 100644 --- a/src/sales/pages/lead_detail.page.ts +++ b/src/sales/pages/lead_detail.page.ts @@ -460,7 +460,6 @@ export const LeadDetailPage: Page = { title: 'Open Tasks', filter: [{ field: 'status', operator: 'not_equals', value: 'completed' }], showViewAll: true, - actions: ['new_task', 'edit', 'complete'], }, }, ], diff --git a/src/sales/translations/es-ES/app.ts b/src/sales/translations/es-ES/app.ts index 1ee9fecc..925a7b84 100644 --- a/src/sales/translations/es-ES/app.ts +++ b/src/sales/translations/es-ES/app.ts @@ -2,9 +2,11 @@ import type { TranslationData } from '@objectstack/spec/system'; +import { QUOTE_DISCOUNT_CEILING } from '../../objects/_thresholds'; + /** * Español (es-ES) — every translation namespace EXCEPT `objects`: - * `apps`, `messages`, `dashboards`, `datasets`, `pages`. + * `apps`, `messages`, `dashboards`, `datasets`, `pages`, `flows`. * * SPLIT AXIS (#1311): translation NAMESPACE first, then CRM DOMAIN FAMILY. * Everything that is not `objects` lives in `./app.ts`; `objects` — 69-78% of @@ -590,4 +592,93 @@ export const appSurface: Omit = { }, }, }, + // Screen-flow copy (#1210, #1975). Keyed `flows..label`, + // `screens..title` and `screens..fields..{label,placeholder}` + // — the keys `os lint`'s `i18n/missing-flow` names, read by the console's + // flow runner since @objectstack 17.7.0 (the spec's `flows` liveness row is + // `live` there). A screen with no authored `title` shows its flow's label in + // every locale, so each `screen_1.title` repeats the flow label. Select + // option labels and screen descriptions are not translatable keys on a + // screen (`FLOW_SCREEN_FIELD_NO_OPTIONS`), so they stay as authored. + // The discount ceiling is interpolated from `QUOTE_DISCOUNT_CEILING`, never + // retyped: the number lives in `_thresholds.ts` alone (#1711). + flows: { + campaign_enrollment: { + label: 'Inscribir miembros en la campaña', + screens: { + screen_1: { + title: 'Inscribir miembros en la campaña', + fields: { + memberSource: { label: 'Tipo de miembro a inscribir' }, + leadStatus: { label: 'Inscribir prospectos con estado' }, + contactDepartment: { label: 'Inscribir contactos del departamento' }, + }, + }, + }, + }, + escalate_case: { + label: 'Escalar Caso', + screens: { screen_1: { title: 'Escalar Caso', fields: { reason: { label: 'Motivo de Escalación' } } } }, + }, + close_case: { + label: 'Cerrar Caso', + screens: { + screen_1: { + title: 'Cerrar Caso', + fields: { + resolution: { label: 'Resolución' }, + resolved_by_article: { label: 'Resuelto con artículo (opcional)' }, + }, + }, + }, + }, + claim_case: { + label: 'Tomar Caso', + screens: { screen_1: { title: 'Tomar Caso', fields: { claimStatus: { label: 'Estado de trabajo' } } } }, + }, + lead_conversion: { + label: 'Proceso de conversión de prospecto', + screens: { + screen_1: { + title: 'Proceso de conversión de prospecto', + fields: { + createOpportunity: { label: '¿Crear oportunidad?' }, + opportunityName: { label: 'Nombre de Oportunidad' }, + opportunityAmount: { label: 'Monto de la Oportunidad' }, + closeDate: { label: 'Fecha de Cierre' }, + }, + }, + refuse_confirmed_duplicate: { title: 'Conversión rechazada' }, + refuse_unapproved: { title: 'Conversión rechazada' }, + }, + }, + schedule_followup: { + label: 'Programar Seguimiento', + screens: { + screen_1: { + title: 'Programar Seguimiento', + fields: { + subject: { label: '¿Cuál es el siguiente paso?' }, + dueDate: { label: 'Fecha Límite' }, + activityType: { label: 'Tipo de Actividad' }, + priority: { label: 'Prioridad' }, + notes: { label: 'Notas' }, + }, + }, + }, + }, + quote_generation: { + label: 'Generar cotización desde la oportunidad', + screens: { + screen_1: { + title: 'Generar cotización desde la oportunidad', + fields: { + quoteName: { label: 'Nombre de Cotización' }, + expirationDays: { label: 'Válida por (días)' }, + discount: { label: `Descuento % (≤ ${QUOTE_DISCOUNT_CEILING})`, placeholder: `0-${QUOTE_DISCOUNT_CEILING}` }, + }, + }, + }, + }, + }, }; diff --git a/src/sales/translations/ja-JP/app.ts b/src/sales/translations/ja-JP/app.ts index 7581188c..435d621a 100644 --- a/src/sales/translations/ja-JP/app.ts +++ b/src/sales/translations/ja-JP/app.ts @@ -2,9 +2,11 @@ import type { TranslationData } from '@objectstack/spec/system'; +import { QUOTE_DISCOUNT_CEILING } from '../../objects/_thresholds'; + /** * 日本語 (ja-JP) — every translation namespace EXCEPT `objects`: - * `apps`, `messages`, `dashboards`, `datasets`, `pages`. + * `apps`, `messages`, `dashboards`, `datasets`, `pages`, `flows`. * * SPLIT AXIS (#1311): translation NAMESPACE first, then CRM DOMAIN FAMILY. * Everything that is not `objects` lives in `./app.ts`; `objects` — 69-78% of @@ -592,4 +594,93 @@ export const appSurface: Omit = { }, }, }, + // Screen-flow copy (#1210, #1975). Keyed `flows..label`, + // `screens..title` and `screens..fields..{label,placeholder}` + // — the keys `os lint`'s `i18n/missing-flow` names, read by the console's + // flow runner since @objectstack 17.7.0 (the spec's `flows` liveness row is + // `live` there). A screen with no authored `title` shows its flow's label in + // every locale, so each `screen_1.title` repeats the flow label. Select + // option labels and screen descriptions are not translatable keys on a + // screen (`FLOW_SCREEN_FIELD_NO_OPTIONS`), so they stay as authored. + // The discount ceiling is interpolated from `QUOTE_DISCOUNT_CEILING`, never + // retyped: the number lives in `_thresholds.ts` alone (#1711). + flows: { + campaign_enrollment: { + label: 'キャンペーンにメンバーを登録', + screens: { + screen_1: { + title: 'キャンペーンにメンバーを登録', + fields: { + memberSource: { label: '登録するメンバーの種類' }, + leadStatus: { label: '登録するリードのステータス' }, + contactDepartment: { label: '登録する取引先責任者の部門' }, + }, + }, + }, + }, + escalate_case: { + label: 'ケースをエスカレート', + screens: { screen_1: { title: 'ケースをエスカレート', fields: { reason: { label: 'エスカレーション理由' } } } }, + }, + close_case: { + label: 'ケースをクローズ', + screens: { + screen_1: { + title: 'ケースをクローズ', + fields: { + resolution: { label: '解決内容' }, + resolved_by_article: { label: '解決に使ったナレッジ記事(任意)' }, + }, + }, + }, + }, + claim_case: { + label: 'ケースを引き受ける', + screens: { screen_1: { title: 'ケースを引き受ける', fields: { claimStatus: { label: '対応状況' } } } }, + }, + lead_conversion: { + label: 'リード変換プロセス', + screens: { + screen_1: { + title: 'リード変換プロセス', + fields: { + createOpportunity: { label: '商談を作成しますか?' }, + opportunityName: { label: '商談名' }, + opportunityAmount: { label: '商談金額' }, + closeDate: { label: '完了予定日' }, + }, + }, + refuse_confirmed_duplicate: { title: '変換は拒否されました' }, + refuse_unapproved: { title: '変換は拒否されました' }, + }, + }, + schedule_followup: { + label: 'フォローアップを設定', + screens: { + screen_1: { + title: 'フォローアップを設定', + fields: { + subject: { label: '次のステップは?' }, + dueDate: { label: '期限' }, + activityType: { label: '活動種別' }, + priority: { label: '優先度' }, + notes: { label: 'メモ' }, + }, + }, + }, + }, + quote_generation: { + label: '商談から見積を作成', + screens: { + screen_1: { + title: '商談から見積を作成', + fields: { + quoteName: { label: '見積名' }, + expirationDays: { label: '有効期間(日)' }, + discount: { label: `割引率 % (≤ ${QUOTE_DISCOUNT_CEILING})`, placeholder: `0-${QUOTE_DISCOUNT_CEILING}` }, + }, + }, + }, + }, + }, }; diff --git a/src/sales/translations/zh-CN/app.ts b/src/sales/translations/zh-CN/app.ts index 5094e693..673cb8e2 100644 --- a/src/sales/translations/zh-CN/app.ts +++ b/src/sales/translations/zh-CN/app.ts @@ -2,9 +2,11 @@ import type { TranslationData } from '@objectstack/spec/system'; +import { QUOTE_DISCOUNT_CEILING } from '../../objects/_thresholds'; + /** * 简体中文 (zh-CN) — every translation namespace EXCEPT `objects`: - * `apps`, `messages`, `dashboards`, `datasets`, `pages`. + * `apps`, `messages`, `dashboards`, `datasets`, `pages`, `flows`. * * SPLIT AXIS (#1311): translation NAMESPACE first, then CRM DOMAIN FAMILY. * Everything that is not `objects` lives in `./app.ts`; `objects` — 69-78% of @@ -591,4 +593,93 @@ export const appSurface: Omit = { }, }, }, + // Screen-flow copy (#1210, #1975). Keyed `flows..label`, + // `screens..title` and `screens..fields..{label,placeholder}` + // — the keys `os lint`'s `i18n/missing-flow` names, read by the console's + // flow runner since @objectstack 17.7.0 (the spec's `flows` liveness row is + // `live` there). A screen with no authored `title` shows its flow's label in + // every locale, so each `screen_1.title` repeats the flow label. Select + // option labels and screen descriptions are not translatable keys on a + // screen (`FLOW_SCREEN_FIELD_NO_OPTIONS`), so they stay as authored. + // The discount ceiling is interpolated from `QUOTE_DISCOUNT_CEILING`, never + // retyped: the number lives in `_thresholds.ts` alone (#1711). + flows: { + campaign_enrollment: { + label: '将成员加入营销活动', + screens: { + screen_1: { + title: '将成员加入营销活动', + fields: { + memberSource: { label: '加入的成员类型' }, + leadStatus: { label: '加入以下状态的线索' }, + contactDepartment: { label: '加入以下部门的联系人' }, + }, + }, + }, + }, + escalate_case: { + label: '升级工单', + screens: { screen_1: { title: '升级工单', fields: { reason: { label: '升级原因' } } } }, + }, + close_case: { + label: '关闭工单', + screens: { + screen_1: { + title: '关闭工单', + fields: { + resolution: { label: '解决方案' }, + resolved_by_article: { label: '通过知识文章解决(可选)' }, + }, + }, + }, + }, + claim_case: { + label: '认领工单', + screens: { screen_1: { title: '认领工单', fields: { claimStatus: { label: '处理状态' } } } }, + }, + lead_conversion: { + label: '线索转化流程', + screens: { + screen_1: { + title: '线索转化流程', + fields: { + createOpportunity: { label: '是否创建商机?' }, + opportunityName: { label: '商机名称' }, + opportunityAmount: { label: '商机金额' }, + closeDate: { label: '预计成交日期' }, + }, + }, + refuse_confirmed_duplicate: { title: '转化被拒绝' }, + refuse_unapproved: { title: '转化被拒绝' }, + }, + }, + schedule_followup: { + label: '安排跟进', + screens: { + screen_1: { + title: '安排跟进', + fields: { + subject: { label: '下一步做什么?' }, + dueDate: { label: '截止日期' }, + activityType: { label: '活动类型' }, + priority: { label: '优先级' }, + notes: { label: '备注' }, + }, + }, + }, + }, + quote_generation: { + label: '从商机生成报价单', + screens: { + screen_1: { + title: '从商机生成报价单', + fields: { + quoteName: { label: '报价名称' }, + expirationDays: { label: '有效期(天)' }, + discount: { label: `折扣 % (≤ ${QUOTE_DISCOUNT_CEILING})`, placeholder: `0-${QUOTE_DISCOUNT_CEILING}` }, + }, + }, + }, + }, + }, }; diff --git a/test/backfill-query-bodies.test.ts b/test/backfill-query-bodies.test.ts index 55b65aeb..1e34f03e 100644 --- a/test/backfill-query-bodies.test.ts +++ b/test/backfill-query-bodies.test.ts @@ -30,8 +30,9 @@ import { REPO_ROOT } from './helpers/repo-root'; * real request code and every query body it sends is captured. Nothing is * exported from the scripts for this, so what gets checked is what the script * actually sends; a body built inline somewhere new is caught too. The stub - * answers sign-in, and judges each query body the way the 17.6.0 REST door - * does (`@objectstack/rest`, the `POST .../:object/query` route): it adds + * answers sign-in, and judges each query body the way the REST door does + * (`@objectstack/rest`, the `POST .../:object/query` route; read on 17.6.0 and + * again on 17.7.0): it adds * `object` to the body, then `FindDataRequestSchema.safeParse({ object, query })`. * An accepted body gets `{ records: [] }`, so the script goes through each of * its objects once and finishes. A refused one gets the door's 400. @@ -44,7 +45,7 @@ const BACKFILL_SCRIPTS = readdirSync(join(REPO_ROOT, 'scripts')) .filter((f) => /^backfill-.+\.ts$/.test(f)) .sort(); -/** The 17.6.0 query door's own check: `object` merged into the body, then the spec schema. */ +/** The query door's own check (read on 17.6.0 and 17.7.0): `object` merged into the body, then the spec schema. */ function door(object: string, body: unknown) { const query = body && typeof body === 'object' && !Array.isArray(body) ? { ...body, object } : body; return FindDataRequestSchema.safeParse({ object, query }); diff --git a/test/cascade-guard-messages.test.ts b/test/cascade-guard-messages.test.ts index e8bf803f..4dffc06d 100644 --- a/test/cascade-guard-messages.test.ts +++ b/test/cascade-guard-messages.test.ts @@ -6,6 +6,8 @@ import { DefaultDatasourcePlugin, AppPlugin } from '@objectstack/runtime'; import { ObjectQLPlugin } from '@objectstack/objectql'; import { MetadataPlugin } from '@objectstack/metadata'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * A guard's refusal must name the record that is refusing — never the record @@ -101,6 +103,9 @@ beforeAll(async () => { await kernel.use(new DefaultDatasourcePlugin({ driver: 'memory', config: {} } as never)); await kernel.use(new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_693' } as never)); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_693' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); // The app's own metadata is the subject — objects and hooks exactly as // `objectstack.config.ts` declares them. Seed data is skipped; each test // builds the population it needs. diff --git a/test/case-guest-branch-leftovers.test.ts b/test/case-guest-branch-leftovers.test.ts index 65b79043..c503df72 100644 --- a/test/case-guest-branch-leftovers.test.ts +++ b/test/case-guest-branch-leftovers.test.ts @@ -13,6 +13,8 @@ import { import { SharingServicePlugin } from '@objectstack/plugin-sharing'; import { tenancyProbe } from './helpers/tenancy-probe'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * The two leftovers #1133 left in the `crm_case` guest branch, pinned on @@ -167,6 +169,9 @@ beforeAll(async () => { new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_test' } as never), ); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_test' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); await kernel.use(new AppPlugin(stack as never, undefined as never, { skipSeedData: true } as never)); await kernel.use( new SecurityPlugin({ diff --git a/test/contract-write-depth.test.ts b/test/contract-write-depth.test.ts index e509fc31..39158a5b 100644 --- a/test/contract-write-depth.test.ts +++ b/test/contract-write-depth.test.ts @@ -14,6 +14,8 @@ import { SharingServicePlugin } from '@objectstack/plugin-sharing'; import { tenancyProbe } from './helpers/tenancy-probe'; import { defineStack, PLATFORM_CAPABILITY_PROVIDERS } from '@objectstack/spec'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * A Sales Manager's WRITE reach on `crm_contract` — the declaration, and what it @@ -211,6 +213,9 @@ beforeAll(async () => { new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_test' } as never), ); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_test' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); await kernel.use(new AppPlugin(stack as never, undefined as never, { skipSeedData: true } as never)); await kernel.use( new SecurityPlugin({ diff --git a/test/flow-scheduled.test.ts b/test/flow-scheduled.test.ts index 1f0cbe14..26e95474 100644 --- a/test/flow-scheduled.test.ts +++ b/test/flow-scheduled.test.ts @@ -868,7 +868,7 @@ describe('re-seed × snapshot leaves one row per (owner, period, window) (#702)' /** * The ownership claim, run for REAL: `claimSeedOwnership` from * `@objectstack/plugin-security`, the function the platform re-runs on - * `app:seeded` once the seed settles (objectstack#17872, in the 17.6.0 pin). + * `app:seeded` once the seed settles (objectstack#17872, shipped in 17.6.0). * It replaced the app's own `demo_bootstrap` sweep (#1892) and hands every * ownerless row of every object declaring `owner_id` to one administrator. * The adapter only maps the harness's `{ modified }` onto the affected-row diff --git a/test/freeze-guard-reference-cleanup.test.ts b/test/freeze-guard-reference-cleanup.test.ts index 7d52530c..5b4d064a 100644 --- a/test/freeze-guard-reference-cleanup.test.ts +++ b/test/freeze-guard-reference-cleanup.test.ts @@ -12,6 +12,8 @@ import oppHooks from '../src/sales/objects/opportunity.hook'; import quoteHooks from '../src/revenue/objects/quote.hook'; import { hookNamed, makeCtx, makeHarness, type Rec } from './helpers/hook-harness'; import { extractSandboxBody } from './helpers/action-sandbox'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * A frozen record must not make the people it references undeletable (#720). @@ -263,6 +265,9 @@ beforeAll(async () => { await kernel.use(new DefaultDatasourcePlugin({ driver: 'memory', config: {} } as never)); await kernel.use(new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_720' } as never)); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_720' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); // The app's own metadata is the subject — objects and hooks exactly as // `objectstack.config.ts` declares them (the rig `cascade-guard-messages` // uses, which is the rig #720 was measured with). diff --git a/test/guest-submission-sanitisation.test.ts b/test/guest-submission-sanitisation.test.ts index 7c351183..02efb637 100644 --- a/test/guest-submission-sanitisation.test.ts +++ b/test/guest-submission-sanitisation.test.ts @@ -13,6 +13,8 @@ import { import { SharingServicePlugin } from '@objectstack/plugin-sharing'; import { tenancyProbe } from './helpers/tenancy-probe'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * What a guest (web-to-case / web-to-lead) submission ACTUALLY stores — pinned @@ -116,6 +118,9 @@ beforeAll(async () => { new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_test' } as never), ); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_test' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); await kernel.use(new AppPlugin(stack as never, undefined as never, { skipSeedData: true } as never)); await kernel.use( new SecurityPlugin({ diff --git a/test/helpers/identity-objects.ts b/test/helpers/identity-objects.ts new file mode 100644 index 00000000..397279ca --- /dev/null +++ b/test/helpers/identity-objects.ts @@ -0,0 +1,44 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * The platform identity objects a reduced test stack has to register for itself + * (ObjectStack 17.7.0). + * + * ### What this exists for + * + * Several files in this suite boot ObjectQL over `objectstack.config.ts` and + * insert `sys_user` fixtures (a real user id is what their hooks and sharing + * rules key on). None mounts `plugin-auth`, because nothing they measure needs + * sign-in — and `plugin-auth` is the plugin that registers `sys_user`, + * `sys_organization`, `sys_member` and their siblings at boot (its manifest's + * `objects`). + * + * Through 17.6.0 the omission was invisible: the engine handed a name its + * registry did not hold to the driver as a table, and the memory driver created + * one on the first write. From 17.7.0 the engine's verbs refuse an unregistered + * object name with `404 OBJECT_NOT_FOUND` before any hook or driver runs + * (objectstack#21545), so the first `insert('sys_user', …)` failed the whole + * file. The release notes' prescription is "register the object first". + * + * This registers the platform's own definitions, imported rather than + * hand-mirrored, through the `manifest` service under the package id + * `plugin-auth` uses — the call `plugin-auth`'s own `init()` makes. + */ +export function identityObjects(...objects: unknown[]) { + return { + name: 'test-identity-objects', + version: '1.0.0', + dependencies: ['com.objectstack.engine.objectql'], + init(ctx: { getService: (name: string) => { register: (manifest: unknown) => void } }): void { + ctx.getService('manifest').register({ + id: 'com.objectstack.plugin-auth', + namespace: 'sys', + version: '1.0.0', + type: 'plugin', + scope: 'system', + name: 'Identity objects (test stand-in for plugin-auth)', + objects, + }); + }, + }; +} diff --git a/test/hierarchy-read-depth.test.ts b/test/hierarchy-read-depth.test.ts index ee41bd92..a86b3b41 100644 --- a/test/hierarchy-read-depth.test.ts +++ b/test/hierarchy-read-depth.test.ts @@ -15,6 +15,8 @@ import { SharingServicePlugin } from '@objectstack/plugin-sharing'; import { tenancyProbe } from './helpers/tenancy-probe'; import { defineStack, PLATFORM_CAPABILITY_PROVIDERS } from '@objectstack/spec'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * The READ half of the hierarchy-scope edition boundary (#1378) — the @@ -279,6 +281,9 @@ beforeAll(async () => { new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_test' } as never), ); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_test' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); await kernel.use(new AppPlugin(stack as never, undefined as never, { skipSeedData: true } as never)); await kernel.use( new SecurityPlugin({ diff --git a/test/knowledge-article-share-links.test.ts b/test/knowledge-article-share-links.test.ts index 9c4d310b..182988fb 100644 --- a/test/knowledge-article-share-links.test.ts +++ b/test/knowledge-article-share-links.test.ts @@ -137,18 +137,22 @@ class TestRouter { method: string, pattern: string, req: { params?: AnyRec; query?: AnyRec; body?: AnyRec; headers?: AnyRec } = {}, - ): Promise<{ status: number; body: AnyRec }> { + ): Promise<{ status: number; body: AnyRec; headers: AnyRec }> { const handler = this.routes.get(`${method} ${pattern}`); if (!handler) throw new Error(`no route registered for ${method} ${pattern}`); let status = 200; let body: AnyRec = {}; + const headers: AnyRec = {}; const res = { status(code: number) { status = code; return res; }, json(payload: AnyRec) { body = payload; return res; }, send(payload: AnyRec) { body = payload; return res; }, + // `IHttpResponse.header` — since 17.7.0 the public resolve route sets + // `Cache-Control: no-store` and `Vary: X-Share-Password` on its answer. + header(name: string, value: string | string[]) { headers[name] = value; return res; }, }; await handler({ params: {}, query: {}, headers: {}, ...req }, res); - return { status, body }; + return { status, body, headers }; } } diff --git a/test/lead-duplicate-link-cleanup.test.ts b/test/lead-duplicate-link-cleanup.test.ts index 0b1154d8..b31e1ab4 100644 --- a/test/lead-duplicate-link-cleanup.test.ts +++ b/test/lead-duplicate-link-cleanup.test.ts @@ -6,6 +6,8 @@ import { DefaultDatasourcePlugin, AppPlugin } from '@objectstack/runtime'; import { ObjectQLPlugin } from '@objectstack/objectql'; import { MetadataPlugin } from '@objectstack/metadata'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * A lead flagged as a duplicate must not make the record it duplicates @@ -178,6 +180,9 @@ beforeAll(async () => { await kernel.use(new DefaultDatasourcePlugin({ driver: 'memory', config: {} } as never)); await kernel.use(new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_1072' } as never)); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_1072' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); // The app's own metadata is the subject — objects and hooks exactly as // `objectstack.config.ts` declares them. A unit test of the handler cannot // show any of this: only the engine decides that `set_null` reaches the lead diff --git a/test/parent-derived-reach.test.ts b/test/parent-derived-reach.test.ts index 14b887fd..ecb1e47c 100644 --- a/test/parent-derived-reach.test.ts +++ b/test/parent-derived-reach.test.ts @@ -13,6 +13,8 @@ import { import { SharingServicePlugin } from '@objectstack/plugin-sharing'; import { tenancyProbe } from './helpers/tenancy-probe'; import stack from '../objectstack.config'; +import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objects/identity'; +import { identityObjects } from './helpers/identity-objects'; /** * What a `controlled_by_parent` child is ACTUALLY reachable by — measured @@ -121,6 +123,9 @@ beforeAll(async () => { await kernel.use(new DefaultDatasourcePlugin({ driver: 'memory', config: {} } as never)); await kernel.use(new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_test' } as never)); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_test' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); // The app's own metadata is the subject: objects, profiles, positions and // sharing rules exactly as `objectstack.config.ts` declares them. Seed data // is skipped — the fixture below is the whole population. @@ -357,7 +362,11 @@ describe('#694: the parent-write gate derives from the master the same way', () await ql.update(object, { id: rowId, ...patch }, { context: repCtx }); return 'allowed'; } catch (error: unknown) { - return `denied: ${(error as AnyRec)?.name}`; + // A refusal with no class of its own is named by its code: since 17.7.0 a + // by-id write to a row the caller cannot READ answers `RECORD_NOT_FOUND` + // (404) — hidden and gone are one answer on the write doors (objectstack#21812). + const e = error as AnyRec; + return `denied: ${e?.name === 'Error' && e?.code ? e.code : e?.name}`; } }; @@ -385,19 +394,23 @@ describe('#694: the parent-write gate derives from the master the same way', () // 17.4.0 the line_JP write succeeded too: the master's own derivation was // not composed in, so a master that was itself controlled_by_parent // resolved to "no restriction" (objectstack#11082). + // The rep cannot read any of these rows (each master chain ends at an + // unreadable account), so since 17.7.0 the write door answers each one as + // absent (`RECORD_NOT_FOUND`, objectstack#21812) rather than 403. Still + // refused at both levels, nothing written. expect( await repWrites('crm_contact', id.contact_JP, { title: 'Head of Ops' }), 'a contact under an unreadable account became writable again — objectstack#5386 regressed', - ).toBe('denied: PermissionDeniedError'); + ).toBe('denied: RECORD_NOT_FOUND'); expect(await repWrites('crm_quote', id.quote_JP, { name: 'x' })).toBe( - 'denied: PermissionDeniedError', + 'denied: RECORD_NOT_FOUND', ); expect( await repWrites('crm_quote_line_item', id.line_JP, { quantity: 2 }), 'a line under a quote under an unreadable account became writable — objectstack#11082 regressed', - ).toBe('denied: PermissionDeniedError'); + ).toBe('denied: RECORD_NOT_FOUND'); expect(await repWrites('crm_opportunity_line_item', id.oli_JP, { quantity: 2 })).toBe( - 'denied: PermissionDeniedError', + 'denied: RECORD_NOT_FOUND', ); }); diff --git a/test/unassigned-case-triage-reach.test.ts b/test/unassigned-case-triage-reach.test.ts index 1faebd2b..5fc79948 100644 --- a/test/unassigned-case-triage-reach.test.ts +++ b/test/unassigned-case-triage-reach.test.ts @@ -16,6 +16,7 @@ import { SysUser, SysMember, SysOrganization } from '@objectstack/platform-objec import stack from '../objectstack.config'; import caseHooks from '../src/service/objects/case.hook'; import { CLAIMABLE_TARGET_STATUSES } from '../src/service/objects/_case-assignment'; +import { identityObjects } from './helpers/identity-objects'; /** * Who really sees the `Unassigned — triage` tab's rows (#1096) — measured @@ -153,6 +154,9 @@ async function boot(driver: string, config: AnyRec): Promise { new MetadataPlugin({ watch: false, artifactWatch: false, environmentId: 'proj_test' } as never), ); await kernel.use(new ObjectQLPlugin({ environmentId: 'proj_test' } as never)); + // 17.7.0 refuses an object name the registry does not hold (objectstack#21545): + // register the identity objects `plugin-auth` would (`test/helpers/identity-objects.ts`). + await kernel.use(identityObjects(SysUser, SysMember, SysOrganization) as never); await kernel.use(new AppPlugin(stack as never, undefined as never, { skipSeedData: true } as never)); await kernel.use( new SecurityPlugin({ @@ -330,7 +334,11 @@ async function boot(driver: string, config: AnyRec): Promise { await ql.update(object, { id: rowId, ...patch }, { context }); return 'allowed'; } catch (error: unknown) { - return `denied: ${(error as AnyRec)?.name}`; + // A refusal with no class of its own is named by its code: since 17.7.0 a + // by-id write to a row the caller cannot READ answers `RECORD_NOT_FOUND` + // (404) — hidden and gone are one answer on the write doors (objectstack#21812). + const e = error as AnyRec; + return `denied: ${e?.name === 'Error' && e?.code ? e.code : e?.name}`; } }; @@ -580,10 +588,13 @@ for (const { label, driver } of DRIVERS) { 'an agent assigned an unowned case to SOMEBODY ELSE — the claim seam is supposed to make ' + 'that unspellable, and the gate is supposed to refuse it', ).toBe('denied: PermissionDeniedError'); + // The agent cannot read a case another agent owns, so since 17.7.0 the + // write door answers it as absent (`RECORD_NOT_FOUND`, objectstack#21812) + // before the transfer gate is reached. Still refused, nothing written. expect( await writes('crm_case', id.other_case, { owner_id: id.agent }), 'an agent grabbed a case owned by somebody else — the transfer gate is not holding', - ).toBe('denied: PermissionDeniedError'); + ).toBe('denied: RECORD_NOT_FOUND'); // Nor can the value ride along with the gesture that IS allowed. expect( await writes('crm_case', id.unowned_open, { status: 'in_progress', owner_id: id.agent }),