{"_id":"@360crewing/marketplace-sdk","_rev":"13-0bd2b4891efbce2343c5df8b2e287b9a","name":"@360crewing/marketplace-sdk","dist-tags":{"latest":"0.5.0"},"versions":{"0.1.3":{"name":"@360crewing/marketplace-sdk","version":"0.1.3","license":"SEE LICENSE IN LICENSE","_id":"@360crewing/marketplace-sdk@0.1.3","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"homepage":"https://dev.360crewing.com","dist":{"shasum":"7b263eafb2a0e808f4a2dc03bc8b5b103f7503a9","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.1.3.tgz","fileCount":29,"integrity":"sha512-KwbzXZlRJpXMVyAoSJz+OviDup0YqvHE1Yut8q3XQhPtdjATlbm7fzEOASp1YGwsnak024Qhd2WaHqn9O7FhpQ==","signatures":[{"sig":"MEUCIFrEq2B9qnq5NJ/kacIUAHj8Slkd/aAgKV7U1WlA0GdwAiEAvK7MZfNrsN3IPjwjItbrv6cOtCq/OnI/sqLL1wNYKZE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44756},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"78acd2a1c2cb8a56cc9eb0925bf34e9d75744a5b","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"_npmVersion":"10.9.2","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","directories":{},"_nodeVersion":"22.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"axios":"^1.9.0","react":"^18.0.0 || ^19.0.0","react-i18next":">=14","@360crewing/ui":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/marketplace-sdk_0.1.3_1780653510836_0.2979278695862664","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@360crewing/marketplace-sdk","version":"0.2.0","license":"SEE LICENSE IN LICENSE","_id":"@360crewing/marketplace-sdk@0.2.0","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"homepage":"https://dev.360crewing.com","dist":{"shasum":"3bced293b1c203c0e7fbeb683dfa8de29babb032","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.2.0.tgz","fileCount":31,"integrity":"sha512-JsL3ArZndd1plpw9bmrO60S2oIG3VIlyw6LLql/B40L8fmRt9gorUl8TaL1po/begepmDuGg2M/r7YS0UByiPQ==","signatures":[{"sig":"MEYCIQDIAv24hYiuxDqAsA7fFc/CoAGCJbPoJxp6qRDIFyutfwIhAN8NDzb4HhTadng/UD2/kco5zqpWyUd/RWTkoiBJCGTH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39092},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./build":{"types":"./dist/buildConfig.d.ts","import":"./dist/buildConfig.js","default":"./dist/buildConfig.js"},"./package.json":"./package.json"},"gitHead":"511c5998fae4dbce414b0d01f0df30dff4173c20","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"_npmVersion":"10.9.2","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","directories":{},"_nodeVersion":"22.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@rsbuild/core":"^2.0.6","@rsbuild/plugin-react":"^2.0.0","@module-federation/rsbuild-plugin":"^2.4.0"},"peerDependencies":{"axios":"^1.9.0","react":"^18.0.0 || ^19.0.0","react-i18next":">=14","@360crewing/ui":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/marketplace-sdk_0.2.0_1782806987828_0.5880546979897818","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@360crewing/marketplace-sdk","version":"0.2.1","license":"SEE LICENSE IN LICENSE","_id":"@360crewing/marketplace-sdk@0.2.1","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"homepage":"https://dev.360crewing.com","dist":{"shasum":"8be5e858986134ec14ccb0bbc03d8429e851dcb9","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.2.1.tgz","fileCount":31,"integrity":"sha512-Gxc46xymxKY/EXIoOulu6HKGs/4jtuztgnAvsJSrBGeA82qhvb237m1vR0gY5apFt5pgsu6XFpVqo7taxZzRmw==","signatures":[{"sig":"MEUCIQCP7xN8sM8cXHBaErWzXg0UyJDLN9K/PgiMT6T7e8P8vAIgbCYANJF+alJvBsjgtTZcM/8nVdfUki3ReM44bYYfgkQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39444},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./build":{"types":"./dist/buildConfig.d.ts","import":"./dist/buildConfig.js","default":"./dist/buildConfig.js"},"./package.json":"./package.json"},"gitHead":"4ed498cdc9a665d9135fb30655f7dc04baa9861f","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"_npmVersion":"10.9.2","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","directories":{},"_nodeVersion":"22.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@rsbuild/core":"^2.0.6","@rsbuild/plugin-react":"^2.0.0","@module-federation/rsbuild-plugin":"^2.4.0"},"peerDependencies":{"axios":"^1.9.0","react":"^18.0.0 || ^19.0.0","react-i18next":">=14","@360crewing/ui":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/marketplace-sdk_0.2.1_1782819393871_0.5839932412610727","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@360crewing/marketplace-sdk","version":"0.3.0","license":"SEE LICENSE IN LICENSE","_id":"@360crewing/marketplace-sdk@0.3.0","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"homepage":"https://dev.360crewing.com","dist":{"shasum":"80ea1d4a3486b1b1a0af7b95a6c911a7ab81ffee","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.3.0.tgz","fileCount":31,"integrity":"sha512-AKwB7ViaPxP19yEYw55eO0nfFlb1PGtiPmhzLZ5wugfJOBFrH+6YzgC23m/2rXUIrbO4B/b0g3+OLEK9HhQHIQ==","signatures":[{"sig":"MEQCIG32vMibrywLV+VaRKoaL4XGxhONg2ca5wPxKccHsQEeAiASd4lbKUKH4654U/YnxtP+IQnCuUOKePKk6Gw7PgjXhg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43611},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./build":{"types":"./dist/buildConfig.d.ts","import":"./dist/buildConfig.js","default":"./dist/buildConfig.js"},"./package.json":"./package.json"},"gitHead":"2844c0b3b6f6293c2bbe69ccd6de11eff67b46ca","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"_npmVersion":"10.9.2","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","directories":{},"_nodeVersion":"22.15.0","dependencies":{"javascript-obfuscator":"^5.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@rsbuild/core":"^2.0.6","@rsbuild/plugin-react":"^2.0.0","@module-federation/rsbuild-plugin":"^2.4.0"},"peerDependencies":{"axios":"^1.9.0","react":"^18.0.0 || ^19.0.0","react-i18next":">=14","@360crewing/ui":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/marketplace-sdk_0.3.0_1782898610936_0.46781002133453","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@360crewing/marketplace-sdk","version":"0.4.0","license":"SEE LICENSE IN LICENSE","_id":"@360crewing/marketplace-sdk@0.4.0","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"homepage":"https://dev.360crewing.com","dist":{"shasum":"736dc997edb1dd908ec4b3c04a819fb537af2277","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.4.0.tgz","fileCount":31,"integrity":"sha512-lkQdencuMrcVtbPk5Tt28Ryr2cQXhe4MQKaY45QwyJbB2FpjcJc6kJcv5xN0Q2wYV32gZ8kXXborbadTx+Wpcg==","signatures":[{"sig":"MEQCICtwCnwvn4miMDW6ar/yoaOT67Yl5l5CS5mpJljkXis9AiBz/jb3sU2MjENfsKB+wYLy1u5V4yMR4F6EnJqj1siU8w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":47177},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./build":{"types":"./dist/buildConfig.d.ts","import":"./dist/buildConfig.js","default":"./dist/buildConfig.js"},"./package.json":"./package.json"},"gitHead":"6d3b182ea91f3f8918b2f0a5eebbc310a2366d70","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"_npmVersion":"10.9.2","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","directories":{},"_nodeVersion":"22.15.0","dependencies":{"javascript-obfuscator":"^5.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@rsbuild/core":"^2.0.6","@rsbuild/plugin-react":"^2.0.0","@module-federation/rsbuild-plugin":"^2.4.0"},"peerDependencies":{"axios":"^1.9.0","react":"^18.0.0 || ^19.0.0","react-i18next":">=14","@360crewing/ui":"^0.1.0 || ^0.2.0"},"_npmOperationalInternal":{"tmp":"tmp/marketplace-sdk_0.4.0_1788360458203_0.5471071140679871","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@360crewing/marketplace-sdk","version":"0.4.1","license":"SEE LICENSE IN LICENSE","_id":"@360crewing/marketplace-sdk@0.4.1","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"homepage":"https://dev.360crewing.com","dist":{"shasum":"ac08a089ae1bbca1fcf5e9332f94e029e96efec5","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.4.1.tgz","fileCount":31,"integrity":"sha512-SbP7FtxML9IWkQpXFeK8OiRQF3q6FHFuRTosuVcLcXEiFenvLPYUYdbPnHV73XKD7ZYeQxbopPlJQbolkIn8KQ==","signatures":[{"sig":"MEUCIFTw+bKH4wH8RpWc5kE0OWiaNq1xzg0B8YraJ6kYLjguAiEAoxfIy3NBLI+d10Op2Oqt/QF0RjThejwUTaPLMTYbiyk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":47187},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./build":{"types":"./dist/buildConfig.d.ts","import":"./dist/buildConfig.js","default":"./dist/buildConfig.js"},"./package.json":"./package.json"},"gitHead":"696e23ca999b479366c255ae290d56243a62d24d","scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"_npmVersion":"10.9.2","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","directories":{},"_nodeVersion":"22.15.0","dependencies":{"javascript-obfuscator":"^5.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@rsbuild/core":"^2.0.6","@rsbuild/plugin-react":"^2.0.0","@module-federation/rsbuild-plugin":"^2.4.0"},"peerDependencies":{"axios":"^1.9.0","react":"^18.0.0 || ^19.0.0","react-i18next":">=14","@360crewing/ui":"^0.1.0 || ^0.2.0 || ^0.3.0"},"_npmOperationalInternal":{"tmp":"tmp/marketplace-sdk_0.4.1_1788361974011_0.6502965231732547","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@360crewing/marketplace-sdk","version":"0.5.0","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","license":"SEE LICENSE IN LICENSE","homepage":"https://dev.360crewing.com","publishConfig":{"access":"public"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./build":{"types":"./dist/buildConfig.d.ts","import":"./dist/buildConfig.js","default":"./dist/buildConfig.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","axios":"^1.9.0","react-i18next":">=14","@360crewing/ui":"^0.1.0 || ^0.2.0 || ^0.3.0"},"dependencies":{"javascript-obfuscator":"^5.4.3"},"devDependencies":{"@rsbuild/core":"^2.0.6","@rsbuild/plugin-react":"^2.0.0","@module-federation/rsbuild-plugin":"^2.4.0"},"_id":"@360crewing/marketplace-sdk@0.5.0","gitHead":"85835912e0ca9c62e35c7df100e59edfda49ade1","_nodeVersion":"22.15.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-ZLiyjlmHDDRoxikErUch5fqVtzLtqjvAC6/Dg7ZglOqYIdW8Z+Y5isSs5ikvQZ5A8+flaVDEbJNpVBIPiTHe5A==","shasum":"bb755c8089a953570da11c87f6ecaedc12ad5c20","tarball":"https://registry.npmjs.org/@360crewing/marketplace-sdk/-/marketplace-sdk-0.5.0.tgz","fileCount":31,"unpackedSize":51372,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC602hoEc1CyV04E/gvWd/v5oaA5pGWGJwuh5aZFAt+5QIhAMKWg9mSEa/2evwhlRxFFFIVeSNyRxYIGHXtV1Cx4H6x"}]},"_npmUser":{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"},"directories":{},"maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/marketplace-sdk_0.5.0_1788769867512_0.0366920350413098"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-05T09:20:24.558Z","modified":"2026-09-07T08:31:07.809Z","0.1.0":"2026-06-05T09:20:24.918Z","0.1.1":"2026-06-05T09:25:00.496Z","0.1.2":"2026-06-05T09:41:14.907Z","0.1.3":"2026-06-05T09:58:30.952Z","0.2.0":"2026-06-30T08:09:48.012Z","0.2.1":"2026-06-30T11:36:34.002Z","0.3.0":"2026-07-01T09:36:51.061Z","0.4.0":"2026-09-02T14:47:38.345Z","0.4.1":"2026-09-02T15:12:54.135Z","0.5.0":"2026-09-07T08:31:07.636Z"},"license":"SEE LICENSE IN LICENSE","homepage":"https://dev.360crewing.com","description":"Public SDK contract for 360crewing marketplace extensions: defineExtension, hooks, slot types.","maintainers":[{"name":"crowdedfuzzball","email":"lukin.dmitriy@gmail.com"}],"readme":"# @360crewing/marketplace-sdk\n\nPublic SDK contract for 360crewing marketplace extensions. This is a\n**contract**: after `0.1.0`, breaking API changes ship only in a major version.\n\n## Install\n\n```bash\nnpm i @360crewing/marketplace-sdk\n```\n\nPeer dependencies (provided by the host via Module Federation `shared` — an\nextension does NOT bundle its own copies): `react`, `axios`, `react-i18next`,\n`@360crewing/ui`.\n\n## Quick start\n\n```tsx\nimport {defineExtension, useUser, useI18n, Card, Button, Slot} from \"@360crewing/marketplace-sdk\";\nimport en from \"./locales/en.json\";\n\n// dashboard.widget — a card on the dashboard (bare component).\nfunction KpiWidget() {\n    const user = useUser();\n    const {t} = useI18n();\n    return (\n        <Card title={t(\"title\")}>\n            <p>{t(\"greeting\", {name: user.full_name})}</p>\n            <Button title={t(\"refresh\")} onClick={() => {}}/>\n        </Card>\n    );\n}\n\n// seafarer.menu — a menu item on the seafarer card + the page it opens.\nfunction CrewAnalyticsPage(props: {seafarer: {uuid: string}}) {\n    return <div>Analytics for seafarer {props.seafarer.uuid}</div>;\n}\n\nexport default defineExtension({\n    id: \"com.acme.crew-analytics\",            // reverse-DNS, unique\n    locales: {en},                            // >=1 locale; files in locales/*.json\n    slots: {\n        [Slot.Dashboard.Widget]: KpiWidget,                       // widget: a component\n        [Slot.Seafarer.Menu]: {                                   // menu: {title,icon?,page}\n            title: \"Crew Analytics\",\n            page: CrewAnalyticsPage,\n        },\n    },\n});\n```\n\n## Slot model\n\nA slot is a named mount point in the host. The slot name = **where** the\nextension appears. Two archetypes:\n\n| Archetype | Slots | What you register |\n|---|---|---|\n| **widget** | `Slot.Dashboard.Widget` | a bare React component (a card in the dashboard grid) |\n| **menu** | `Slot.Seafarer.Menu`, `Slot.Vessel.Menu`, `Slot.Contract.Menu`, `Slot.Nav.{Admin,Data,Finance,Fleet,Reports}.Menu` | `MenuRegistration { title, icon?, page }` |\n\n- `Slot` is a nested namespace (one import): `Slot.Seafarer.Menu`,\n  `Slot.Nav.Data.Menu`, `Slot.Dashboard.Widget`. A raw string key\n  (`\"seafarer.menu\"`) is also accepted and type-safe.\n- **menu slot**: `title` is the item label, `page` is the page component the\n  host renders on click (the route is derived from the extension `id`).\n- One extension can occupy several slots; several extensions in one slot →\n  several menu items.\n- Context in props: widget → `{ widget:{id,settings}, sdk }`; entity-menu →\n  `{ seafarer|vessel|contract:{uuid}, sdk }`; nav-menu → `{ sdk }`.\n\n`defineExtension` validates: reverse-DNS `id`, >=1 locale, >=1 slot, and that a\nmenu slot is `{ title, page }`.\n\n## i18n\n\n- Text lives in `locales/<lang>.json`; `defineExtension({ locales: { en, ru } })`.\n- The host registers them as the i18next namespace `app.<id>` on load.\n- `useI18n()` is `react-i18next` bound to that namespace:\n  `const {t} = useI18n(); t(\"title\")`. Content re-renders when the user changes\n  language (no reload).\n- No translation for the active language → falls back to the host default.\n\n## Storage\n\nThe platform gives an extension **two primitives** (no backend of your own):\n\n**`useUserSettings()` / `sdk.userSettings`** — per-user settings (saved filters,\nUI prefs). Small JSON, last-write-wins, scoped per user.\n\n```tsx\nconst us = useUserSettings<{ visaFilter?: object }>();\nawait us.set({ visaFilter });             // shallow-merge\nconst { visaFilter } = await us.get();    // whole document\n```\n\n**`useDb()` / `sdk.db`** — the extension's own database: one isolated SQLite\nfile per `(tenant, installation)`. **Full SQL**, the extension owns its schema.\n`query` (SELECT), `exec` (INSERT/UPDATE/DELETE/DDL), `tx`.\n\n```tsx\nconst db = useDb();\n\n// schema — once (on install / migration)\nawait db.exec(`CREATE TABLE IF NOT EXISTS visa(\n  id INTEGER PRIMARY KEY, seafarer_uuid TEXT, country TEXT,\n  status TEXT, applied_at TEXT, docs JSON)`);\n\n// CREATE\nawait db.exec(\n  `INSERT INTO visa(seafarer_uuid,country,status,applied_at,docs) VALUES(?,?,?,?,?)`,\n  [uuid, \"US\", \"pending\", \"2026-05-18\", JSON.stringify([\"passport\",\"photo\"])]);\n\n// READ + filter, including an array column (JSON1)\nconst rows = await db.query(`\n  SELECT * FROM visa\n  WHERE status IN ('pending','submitted') AND country = ?\n    AND EXISTS (SELECT 1 FROM json_each(docs) WHERE value = 'passport')\n  ORDER BY applied_at DESC LIMIT 50`, [\"US\"]);\n\n// UPDATE / DELETE / transaction\nawait db.exec(`UPDATE visa SET status=? WHERE id=?`, [\"approved\", 1]);\nawait db.tx(async (t) => {\n  await t.exec(`DELETE FROM visa WHERE status='rejected'`);\n  await t.exec(`INSERT INTO audit(ts) VALUES(?)`, [Date.now()]);\n});\n```\n\nIsolation: the server derives `tenant`/`installation` from the app-JWT, not the\nrequest body; SQL is pinned to that file — no cross-extension data. Host guards:\nSQLite authorizer denylist (no `ATTACH`/`load_extension`/file pragmas),\nper-query timeout, result cap, file quota, write serialization. The SQLite\ndialect is a stable public contract.\n\n## What's included\n\n| Group | API |\n|---|---|\n| Entry point | `defineExtension({ id, locales, slots, onActivate?, onDeactivate? })` |\n| Hooks | `usePlatform`, `useUser`, `useTenant`, `useNotify`, `useModal`, `useConfirm`, `useForm`, `useTheme`, `useI18n`, `useNavigate`, `useUsage`, `useDb`, `useUserSettings` |\n| Slots | `Slot.*` + `MenuRegistration` + context types (`DashboardWidgetContext`, `SeafarerMenuContext`, `VesselMenuContext`, `ContractMenuContext`, `NavMenuContext`) |\n| UI | re-exports all `@360crewing/ui` primitives (`Button`, `Card`, `TextField`, …) |\n\n## Boundaries\n\n- Hooks are the **only** way to use host services (Modal / Toast / Confirm /\n  Form / platform data / i18n / navigation). Extensions have no direct access to\n  host managers.\n- `usePlatform()` is a typed client for platform data\n  (`platform.seafarers/vessels/contracts` → `.list()` / `.search(params)` /\n  `.get(uuid)`). No hand-written URLs or JSON; the host injects an app-scoped\n  JWT and the server checks scope. No raw axios.\n- `useNavigate()` navigates the host app (host-absolute paths).\n- Hooks work only inside a component the host mounted into a slot. Calling them\n  at module scope throws a clear error.\n\n## Building & shipping an extension\n\nAn extension is a Module Federation **remote**, built with the reference MF\ntooling (Rsbuild/Rspack, `@module-federation/rsbuild-plugin`), that **exposes**\n`./extension` = the default export of `defineExtension(...)`. `@360crewing/*` and\n`react` are declared `shared` (`import:false`) so the extension always uses the\nhost's instance (deduped across the MF boundary). A working reference lives in\nthis package's `example/` directory (`rsbuild.config.ts` + `locales/`).\n","readmeFilename":"README.md"}