@kernhq/module-inventory 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -9
- package/dist/contract/capabilities.d.ts +49 -0
- package/dist/contract/capabilities.d.ts.map +1 -0
- package/dist/contract/capabilities.js +52 -0
- package/dist/contract/capabilities.js.map +1 -0
- package/dist/contract/events.d.ts +33 -0
- package/dist/contract/events.d.ts.map +1 -0
- package/dist/contract/events.js +22 -0
- package/dist/contract/events.js.map +1 -0
- package/dist/contract/index.d.ts +15 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +15 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/models.d.ts +146 -0
- package/dist/contract/models.d.ts.map +1 -0
- package/dist/contract/models.js +107 -0
- package/dist/contract/models.js.map +1 -0
- package/dist/contract/permissions.d.ts +22 -0
- package/dist/contract/permissions.d.ts.map +1 -0
- package/dist/contract/permissions.js +26 -0
- package/dist/contract/permissions.js.map +1 -0
- package/dist/{contract.d.ts → contract/router.d.ts} +24 -85
- package/dist/contract/router.d.ts.map +1 -0
- package/dist/contract/router.js +42 -0
- package/dist/contract/router.js.map +1 -0
- package/dist/contract/settings.d.ts +18 -0
- package/dist/contract/settings.d.ts.map +1 -0
- package/dist/contract/settings.js +29 -0
- package/dist/contract/settings.js.map +1 -0
- package/dist/server/index.d.ts +4 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +9 -13
- package/dist/server/index.js.map +1 -1
- package/dist/server/{_impl.d.ts → router.d.ts} +33 -8
- package/dist/server/{_impl.d.ts.map → router.d.ts.map} +1 -1
- package/dist/server/router.js +83 -0
- package/dist/server/router.js.map +1 -0
- package/dist/server/schema.d.ts +25 -11
- package/dist/server/schema.d.ts.map +1 -1
- package/dist/server/schema.js +28 -10
- package/dist/server/schema.js.map +1 -1
- package/dist/server/services/assets.d.ts +73 -0
- package/dist/server/services/assets.d.ts.map +1 -0
- package/dist/server/services/assets.js +261 -0
- package/dist/server/services/assets.js.map +1 -0
- package/dist/server/services/index.d.ts +10 -0
- package/dist/server/services/index.d.ts.map +1 -0
- package/dist/server/services/index.js +15 -0
- package/dist/server/services/index.js.map +1 -0
- package/dist/server/services/notify.d.ts +63 -0
- package/dist/server/services/notify.d.ts.map +1 -0
- package/dist/server/services/notify.js +105 -0
- package/dist/server/services/notify.js.map +1 -0
- package/migrations/0000_init.sql +12 -3
- package/migrations/0001_rls.sql +24 -0
- package/migrations/meta/0000_snapshot.json +40 -13
- package/migrations/meta/_journal.json +2 -2
- package/package.json +12 -9
- package/src/client/api.ts +1 -1
- package/src/client/components/AssetFormDialog.svelte +130 -47
- package/src/client/i18n.ts +11 -166
- package/src/client/index.ts +8 -1
- package/src/client/messages.test.ts +169 -0
- package/src/client/messages.ts +399 -0
- package/src/client/mock.test.ts +161 -0
- package/src/client/mock.ts +267 -45
- package/src/client/module.ts +22 -2
- package/src/client/pages/AssetsPage.svelte +358 -137
- package/src/client/permissions.ts +1 -1
- package/src/client/price.test.ts +106 -0
- package/src/client/price.ts +135 -0
- package/src/client/query.test.ts +58 -0
- package/src/client/query.ts +15 -2
- package/src/client/settings/GeneralSettings.svelte +0 -0
- package/src/client/settings/core-api.ts +32 -0
- package/src/client/widgets/OverviewWidget.svelte +16 -3
- package/src/contract/capabilities.ts +55 -0
- package/src/contract/events.ts +34 -0
- package/src/contract/index.ts +15 -0
- package/src/contract/models.ts +123 -0
- package/src/contract/permissions.ts +26 -0
- package/src/contract/router.ts +46 -0
- package/src/contract/settings.ts +30 -0
- package/src/module.test.ts +140 -7
- package/src/server/index.ts +16 -13
- package/src/server/inventory.int.test.ts +819 -0
- package/src/server/migrations.test.ts +138 -0
- package/src/server/router.ts +118 -0
- package/src/server/schema.ts +27 -10
- package/src/server/services/assets.ts +368 -0
- package/src/server/services/index.ts +23 -0
- package/src/server/services/notify.ts +151 -0
- package/tsconfig.base.json +22 -0
- package/tsconfig.client.json +1 -1
- package/tsconfig.json +1 -1
- package/vitest.config.ts +18 -3
- package/dist/contract.d.ts.map +0 -1
- package/dist/contract.js +0 -119
- package/dist/contract.js.map +0 -1
- package/dist/server/_impl.js +0 -204
- package/dist/server/_impl.js.map +0 -1
- package/src/contract.ts +0 -143
- package/src/server/_impl.ts +0 -275
package/README.md
CHANGED
|
@@ -1,16 +1,62 @@
|
|
|
1
1
|
# @kernhq/module-inventory
|
|
2
2
|
|
|
3
|
-
The asset register for [Kern](https://github.com/KernAIO/app): what the company owns,
|
|
4
|
-
item
|
|
3
|
+
The asset register for [Kern](https://github.com/KernAIO/app): a list of what the company owns, item
|
|
4
|
+
by item.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- **History**: every change to an asset is recorded as an append-only timeline entry: what moved,
|
|
11
|
-
from what, to what, by whom.
|
|
6
|
+
This is a first-party Kern module. Contract, server, screens, strings and manifest ship in one
|
|
7
|
+
package — `core` imports `inventoryModule`, the app shell registers `inventoryClientModule`, and
|
|
8
|
+
deleting the package removes the feature completely. Enable it per workspace in
|
|
9
|
+
**Settings → Modules**.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## What it does today
|
|
12
|
+
|
|
13
|
+
An **asset** carries an asset tag the server assigns (`INV-0042`), a name and description, a serial
|
|
14
|
+
number, a purchase date and vendor, a price, a warranty expiry, a location, a photo and a status.
|
|
15
|
+
|
|
16
|
+
The status column holds one of `in_stock`, `assigned`, `reserved`, `under_repair`, `lost` and
|
|
17
|
+
`retired`, and the screen can filter by any of them — but until custody and repairs ship, nothing
|
|
18
|
+
sets it, so every asset is `in_stock` and the other five filters correctly return nothing. The
|
|
19
|
+
filter is not wrong; there is simply nothing else to find yet.
|
|
20
|
+
|
|
21
|
+
- The **Assets** screen lists them in a table, searches by name, tag or serial number, filters by
|
|
22
|
+
status, hides archived rows until the switch asks for them, and pages a workspace with more
|
|
23
|
+
assets than one screen holds. All four are one server query; nothing is filtered in the browser.
|
|
24
|
+
- Adding an asset opens a dialog, and editing one opens the same dialog seeded from the row. The tag
|
|
25
|
+
is the server's job — people read tags off stickers rather than inventing them.
|
|
26
|
+
- Each row carries a menu: edit, archive, restore. Archiving asks first and names what it is about
|
|
27
|
+
to archive; restoring does not, because it takes nothing away.
|
|
28
|
+
- A **dashboard card** shows the most recently added assets.
|
|
29
|
+
- **Settings → Inventory → General** sets the shape of an asset tag — the prefix and how many digits
|
|
30
|
+
it is padded to, so a workspace that already labels its laptops `LT-` keeps doing that. The number
|
|
31
|
+
itself is a counter in the database rather than a setting: a number an administrator can edit is a
|
|
32
|
+
number that produces a duplicate tag.
|
|
33
|
+
- Two permissions gate it: `inventory.asset.view` and `inventory.asset.manage`.
|
|
34
|
+
- Its strings ship in the five languages the platform speaks — English, Arabic, German, Persian,
|
|
35
|
+
Turkish.
|
|
36
|
+
|
|
37
|
+
The whole API is five procedures under `/api/inventory`: list, get, create, update and archive an
|
|
38
|
+
asset. An asset's photo is settable through `create` and `update` and by nothing on the screen yet;
|
|
39
|
+
its custom values are settable by neither, and wait on custom fields below.
|
|
40
|
+
|
|
41
|
+
## Not built yet
|
|
42
|
+
|
|
43
|
+
Nothing here has a screen. Most of it is a table in `mod_inventory` and nothing more; each bullet
|
|
44
|
+
says how far it actually got. A register is worth designing whole, and a migration that adds a
|
|
45
|
+
column later is cheaper than one that reshapes a table. A table is not a feature, and this section
|
|
46
|
+
stays until each one ships.
|
|
47
|
+
|
|
48
|
+
- **Custody** — who is holding an item now, who held it before, and handing it on.
|
|
49
|
+
- **History** — an append-only timeline of every change to an asset. The writes exist: create,
|
|
50
|
+
update, archive and restore each append an `asset_history` row, and the integration suite holds
|
|
51
|
+
them to it. Nothing reads them back — there is no procedure and no screen.
|
|
52
|
+
- **Repairs** — what went away for repair, to whom, what it cost and when it came back.
|
|
53
|
+
- **Categories** — the column and the list filter exist; nothing can create a category.
|
|
54
|
+
- **Custom fields** — a workspace's own fields on an asset. `assets.custom` holds the values;
|
|
55
|
+
nothing defines a field, so `create` and `update` refuse to write into it at all.
|
|
56
|
+
- **Attachments** — receipts, warranties and manuals against an asset or a repair.
|
|
57
|
+
|
|
58
|
+
Further off, and with nothing in the schema yet: locations and stock control (bins, counts, reorder
|
|
59
|
+
points), purchasing, depreciation, and reservations.
|
|
14
60
|
|
|
15
61
|
## Developing
|
|
16
62
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much Inventory this workspace has.
|
|
3
|
+
*
|
|
4
|
+
* The module answers two questions that look like one: *what do we own and who has it* (an office
|
|
5
|
+
* with forty laptops) and *how much of this do we have and where* (a warehouse with bins and
|
|
6
|
+
* reorder points). Both are "things the company has", both want the same categories, locations,
|
|
7
|
+
* suppliers, attachments and search — and almost nobody wants both halves at once. Capabilities are
|
|
8
|
+
* what keep the small case small: an office switches on nothing beyond the register and never meets
|
|
9
|
+
* the word "bin".
|
|
10
|
+
*
|
|
11
|
+
* **Declared here only once something is behind it.** A switch that changes nothing teaches an
|
|
12
|
+
* administrator that the switchboard does not mean anything, so this list grows with the module.
|
|
13
|
+
*
|
|
14
|
+
* Two rules decide whether something belongs here at all:
|
|
15
|
+
*
|
|
16
|
+
* - **Not a permission.** "May Ada write off a laptop" is a permission — true for her, false for
|
|
17
|
+
* somebody else, in the same workspace. "Does this company track stock levels" is a capability:
|
|
18
|
+
* one answer for everyone, the owner included, and the answer is 404 rather than 403.
|
|
19
|
+
* - **Reversible without a migration.** Switching one off writes a boolean into module settings and
|
|
20
|
+
* the rows stay exactly where they are. Anything that would need data thrown away to reverse is
|
|
21
|
+
* not a capability, however much it looks like one.
|
|
22
|
+
*
|
|
23
|
+
* The rest arrive with the work that makes them mean something: `repairs`, `attachments` and
|
|
24
|
+
* `labels` with the finished register; `custom_fields` and `locations` beside them; `stock` and
|
|
25
|
+
* `procurement` with stock control; `depreciation` and `reservations` last. Adding one here before
|
|
26
|
+
* its procedures exist is the mistake this comment is here to prevent.
|
|
27
|
+
*/
|
|
28
|
+
export declare const inventoryCapabilities: readonly {
|
|
29
|
+
id: string;
|
|
30
|
+
label: string;
|
|
31
|
+
dependsOn: string[];
|
|
32
|
+
defaultEnabled: boolean;
|
|
33
|
+
level: 3 | 1 | 2;
|
|
34
|
+
required: boolean;
|
|
35
|
+
description?: string | undefined;
|
|
36
|
+
}[];
|
|
37
|
+
export type InventoryCapabilityId = (typeof inventoryCapabilities)[number]['id'];
|
|
38
|
+
/**
|
|
39
|
+
* Which procedures sit behind which capability.
|
|
40
|
+
*
|
|
41
|
+
* Declared as data because a missing `requiresCapability` is invisible: the procedure compiles,
|
|
42
|
+
* every other test passes, and the only symptom is a workspace calling a feature it switched off.
|
|
43
|
+
* `module.test.ts` reads this and fails when a procedure named here is not carrying the middleware.
|
|
44
|
+
*
|
|
45
|
+
* A procedure absent from this map belongs to the module as a whole and is reachable whenever
|
|
46
|
+
* Inventory is on — which for `core` is always, because it is `required`.
|
|
47
|
+
*/
|
|
48
|
+
export declare const inventoryCapabilityProcedures: Record<string, readonly string[]>;
|
|
49
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/contract/capabilities.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;GAWhC,CAAA;AAEF,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAA;AAEhF;;;;;;;;;GASG;AACH,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAM,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { defineCapabilities } from '@kernhq/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* How much Inventory this workspace has.
|
|
4
|
+
*
|
|
5
|
+
* The module answers two questions that look like one: *what do we own and who has it* (an office
|
|
6
|
+
* with forty laptops) and *how much of this do we have and where* (a warehouse with bins and
|
|
7
|
+
* reorder points). Both are "things the company has", both want the same categories, locations,
|
|
8
|
+
* suppliers, attachments and search — and almost nobody wants both halves at once. Capabilities are
|
|
9
|
+
* what keep the small case small: an office switches on nothing beyond the register and never meets
|
|
10
|
+
* the word "bin".
|
|
11
|
+
*
|
|
12
|
+
* **Declared here only once something is behind it.** A switch that changes nothing teaches an
|
|
13
|
+
* administrator that the switchboard does not mean anything, so this list grows with the module.
|
|
14
|
+
*
|
|
15
|
+
* Two rules decide whether something belongs here at all:
|
|
16
|
+
*
|
|
17
|
+
* - **Not a permission.** "May Ada write off a laptop" is a permission — true for her, false for
|
|
18
|
+
* somebody else, in the same workspace. "Does this company track stock levels" is a capability:
|
|
19
|
+
* one answer for everyone, the owner included, and the answer is 404 rather than 403.
|
|
20
|
+
* - **Reversible without a migration.** Switching one off writes a boolean into module settings and
|
|
21
|
+
* the rows stay exactly where they are. Anything that would need data thrown away to reverse is
|
|
22
|
+
* not a capability, however much it looks like one.
|
|
23
|
+
*
|
|
24
|
+
* The rest arrive with the work that makes them mean something: `repairs`, `attachments` and
|
|
25
|
+
* `labels` with the finished register; `custom_fields` and `locations` beside them; `stock` and
|
|
26
|
+
* `procurement` with stock control; `depreciation` and `reservations` last. Adding one here before
|
|
27
|
+
* its procedures exist is the mistake this comment is here to prevent.
|
|
28
|
+
*/
|
|
29
|
+
export const inventoryCapabilities = defineCapabilities([
|
|
30
|
+
{
|
|
31
|
+
id: 'core',
|
|
32
|
+
label: 'Assets',
|
|
33
|
+
// Says only what the module answers today. Custody and the change history are what the schema
|
|
34
|
+
// is shaped for and neither has a procedure yet, so naming them here promised a workspace two
|
|
35
|
+
// features it would then go looking for.
|
|
36
|
+
description: 'The asset register: what the company owns, item by item',
|
|
37
|
+
required: true,
|
|
38
|
+
level: 1,
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
/**
|
|
42
|
+
* Which procedures sit behind which capability.
|
|
43
|
+
*
|
|
44
|
+
* Declared as data because a missing `requiresCapability` is invisible: the procedure compiles,
|
|
45
|
+
* every other test passes, and the only symptom is a workspace calling a feature it switched off.
|
|
46
|
+
* `module.test.ts` reads this and fails when a procedure named here is not carrying the middleware.
|
|
47
|
+
*
|
|
48
|
+
* A procedure absent from this map belongs to the module as a whole and is reachable whenever
|
|
49
|
+
* Inventory is on — which for `core` is always, because it is `required`.
|
|
50
|
+
*/
|
|
51
|
+
export const inventoryCapabilityProcedures = {};
|
|
52
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/contract/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;IACtD;QACE,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,QAAQ;QACf,8FAA8F;QAC9F,8FAA8F;QAC9F,yCAAyC;QACzC,WAAW,EAAE,yDAAyD;QACtE,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC;KACT;CACF,CAAC,CAAA;AAIF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAsC,EAAE,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* `<module>.<entity>.<action>`. Anything that emits one declares it here.
|
|
4
|
+
*
|
|
5
|
+
* Payloads carry **ids, never rows**. A subscriber that needs the record asks for it with its own
|
|
6
|
+
* principal, so an event cannot become a way to read data past a permission check.
|
|
7
|
+
*/
|
|
8
|
+
export declare const inventoryEvents: {
|
|
9
|
+
assetCreated: import("@kernhq/contracts").EventDef<"inventory.asset.created", z.ZodObject<{
|
|
10
|
+
assetId: z.ZodUUID;
|
|
11
|
+
workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
assetUpdated: import("@kernhq/contracts").EventDef<"inventory.asset.updated", z.ZodObject<{
|
|
14
|
+
assetId: z.ZodUUID;
|
|
15
|
+
workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
|
|
16
|
+
}, z.core.$strip>>;
|
|
17
|
+
assetArchived: import("@kernhq/contracts").EventDef<"inventory.asset.archived", z.ZodObject<{
|
|
18
|
+
assetId: z.ZodUUID;
|
|
19
|
+
workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
/**
|
|
22
|
+
* The other half of `archive`, which is also the restore path (`archived: false`).
|
|
23
|
+
*
|
|
24
|
+
* One procedure emitting `archived` whichever way the flag pointed told every subscriber that a
|
|
25
|
+
* restored item had just been retired — and the module's own `asset_history` row already knew
|
|
26
|
+
* better, recording `retired` and `restored` separately.
|
|
27
|
+
*/
|
|
28
|
+
assetRestored: import("@kernhq/contracts").EventDef<"inventory.asset.restored", z.ZodObject<{
|
|
29
|
+
assetId: z.ZodUUID;
|
|
30
|
+
workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
|
|
31
|
+
}, z.core.$strip>>;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/contract/events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;IAa1B;;;;;;OAMG;;;;;CAKJ,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineEvent, WorkspaceId } from '@kernhq/contracts';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* `<module>.<entity>.<action>`. Anything that emits one declares it here.
|
|
5
|
+
*
|
|
6
|
+
* Payloads carry **ids, never rows**. A subscriber that needs the record asks for it with its own
|
|
7
|
+
* principal, so an event cannot become a way to read data past a permission check.
|
|
8
|
+
*/
|
|
9
|
+
export const inventoryEvents = {
|
|
10
|
+
assetCreated: defineEvent('inventory.asset.created', z.object({ assetId: z.uuid(), workspaceId: WorkspaceId })),
|
|
11
|
+
assetUpdated: defineEvent('inventory.asset.updated', z.object({ assetId: z.uuid(), workspaceId: WorkspaceId })),
|
|
12
|
+
assetArchived: defineEvent('inventory.asset.archived', z.object({ assetId: z.uuid(), workspaceId: WorkspaceId })),
|
|
13
|
+
/**
|
|
14
|
+
* The other half of `archive`, which is also the restore path (`archived: false`).
|
|
15
|
+
*
|
|
16
|
+
* One procedure emitting `archived` whichever way the flag pointed told every subscriber that a
|
|
17
|
+
* restored item had just been retired — and the module's own `asset_history` row already knew
|
|
18
|
+
* better, recording `retired` and `restored` separately.
|
|
19
|
+
*/
|
|
20
|
+
assetRestored: defineEvent('inventory.asset.restored', z.object({ assetId: z.uuid(), workspaceId: WorkspaceId })),
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/contract/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,YAAY,EAAE,WAAW,CACvB,yBAAyB,EACzB,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAC1D;IACD,YAAY,EAAE,WAAW,CACvB,yBAAyB,EACzB,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAC1D;IACD,aAAa,EAAE,WAAW,CACxB,0BAA0B,EAC1B,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAC1D;IACD;;;;;;OAMG;IACH,aAAa,EAAE,WAAW,CACxB,0BAA0B,EAC1B,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAC1D;CACF,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this module offers, as data.
|
|
3
|
+
*
|
|
4
|
+
* A barrel and nothing else: every symbol is defined in the file beside it. Imported by **both**
|
|
5
|
+
* halves — the server implements the contract, the client calls it — so nothing reachable from here
|
|
6
|
+
* may touch Node. A procedure that exists here and not in the router is a lie that compiles, and
|
|
7
|
+
* `module.test.ts` checks exactly that.
|
|
8
|
+
*/
|
|
9
|
+
export * from './capabilities.js';
|
|
10
|
+
export * from './events.js';
|
|
11
|
+
export * from './models.js';
|
|
12
|
+
export * from './permissions.js';
|
|
13
|
+
export * from './router.js';
|
|
14
|
+
export * from './settings.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this module offers, as data.
|
|
3
|
+
*
|
|
4
|
+
* A barrel and nothing else: every symbol is defined in the file beside it. Imported by **both**
|
|
5
|
+
* halves — the server implements the contract, the client calls it — so nothing reachable from here
|
|
6
|
+
* may touch Node. A procedure that exists here and not in the router is a lie that compiles, and
|
|
7
|
+
* `module.test.ts` checks exactly that.
|
|
8
|
+
*/
|
|
9
|
+
export * from './capabilities.js';
|
|
10
|
+
export * from './events.js';
|
|
11
|
+
export * from './models.js';
|
|
12
|
+
export * from './permissions.js';
|
|
13
|
+
export * from './router.js';
|
|
14
|
+
export * from './settings.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The nouns this module owns, and the shapes that cross the wire.
|
|
4
|
+
*
|
|
5
|
+
* Imported by **both** halves — the server implements against them, the client calls against them —
|
|
6
|
+
* so nothing here may touch Node. Types only; the procedures live in `router.ts`.
|
|
7
|
+
*/
|
|
8
|
+
/** Lowercase, 2-32 characters. Names the API prefix, the Postgres schema `mod_<id>` and every event. */
|
|
9
|
+
export declare const MODULE_ID = "inventory";
|
|
10
|
+
/**
|
|
11
|
+
* An asset's lifecycle. `in_stock` and `assigned` follow custody (an open row in `custody_periods`
|
|
12
|
+
* means assigned); `under_repair` follows an open repair; `reserved` follows a booking that has not
|
|
13
|
+
* been collected; `lost` and `retired` are set by hand when an item stops being usable.
|
|
14
|
+
*
|
|
15
|
+
* Stored rather than derived, because every list filter asks for it — and kept in step inside the
|
|
16
|
+
* same transaction that writes the row it derives from, never by a job afterwards.
|
|
17
|
+
*/
|
|
18
|
+
export declare const AssetStatus: z.ZodEnum<{
|
|
19
|
+
in_stock: "in_stock";
|
|
20
|
+
assigned: "assigned";
|
|
21
|
+
reserved: "reserved";
|
|
22
|
+
under_repair: "under_repair";
|
|
23
|
+
lost: "lost";
|
|
24
|
+
retired: "retired";
|
|
25
|
+
}>;
|
|
26
|
+
export type AssetStatus = z.infer<typeof AssetStatus>;
|
|
27
|
+
/**
|
|
28
|
+
* A value a workspace defined for itself, stored under its `key` in `assets.custom`.
|
|
29
|
+
*
|
|
30
|
+
* `unknown` rather than a union: the field definition says what the type is, and validating a value
|
|
31
|
+
* against a definition the client may not have loaded yet would fail honest input. The server checks
|
|
32
|
+
* it against `field_defs` before writing.
|
|
33
|
+
*/
|
|
34
|
+
export declare const CustomValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
35
|
+
export type CustomValues = z.infer<typeof CustomValues>;
|
|
36
|
+
export declare const Asset: z.ZodObject<{
|
|
37
|
+
id: z.ZodUUID;
|
|
38
|
+
workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
|
|
39
|
+
code: z.ZodString;
|
|
40
|
+
name: z.ZodString;
|
|
41
|
+
description: z.ZodString;
|
|
42
|
+
categoryId: z.ZodNullable<z.ZodUUID>;
|
|
43
|
+
status: z.ZodEnum<{
|
|
44
|
+
in_stock: "in_stock";
|
|
45
|
+
assigned: "assigned";
|
|
46
|
+
reserved: "reserved";
|
|
47
|
+
under_repair: "under_repair";
|
|
48
|
+
lost: "lost";
|
|
49
|
+
retired: "retired";
|
|
50
|
+
}>;
|
|
51
|
+
custodianUserId: z.ZodNullable<z.ZodUUID>;
|
|
52
|
+
custodySince: z.ZodNullable<z.ZodString>;
|
|
53
|
+
serialNumber: z.ZodNullable<z.ZodString>;
|
|
54
|
+
location: z.ZodNullable<z.ZodString>;
|
|
55
|
+
purchasedOn: z.ZodNullable<z.ZodString>;
|
|
56
|
+
purchasedFrom: z.ZodNullable<z.ZodString>;
|
|
57
|
+
priceMinor: z.ZodNullable<z.ZodNumber>;
|
|
58
|
+
currency: z.ZodNullable<z.ZodString>;
|
|
59
|
+
warrantyUntil: z.ZodNullable<z.ZodString>;
|
|
60
|
+
photoFileId: z.ZodNullable<z.ZodUUID>;
|
|
61
|
+
custom: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
62
|
+
createdAt: z.ZodString;
|
|
63
|
+
updatedAt: z.ZodString;
|
|
64
|
+
archivedAt: z.ZodNullable<z.ZodString>;
|
|
65
|
+
}, z.core.$strip>;
|
|
66
|
+
export type Asset = z.infer<typeof Asset>;
|
|
67
|
+
/**
|
|
68
|
+
* How a list is ordered, and therefore what a page cursor is a bookmark *into*.
|
|
69
|
+
*
|
|
70
|
+
* Exported rather than written inline in `router.ts` because the server validates a cursor against
|
|
71
|
+
* this same list: a bookmark issued under one sort is meaningless under another, and the only way
|
|
72
|
+
* to say so is for both halves to read one enum.
|
|
73
|
+
*/
|
|
74
|
+
export declare const AssetSort: z.ZodEnum<{
|
|
75
|
+
code: "code";
|
|
76
|
+
name: "name";
|
|
77
|
+
recent: "recent";
|
|
78
|
+
}>;
|
|
79
|
+
export type AssetSort = z.infer<typeof AssetSort>;
|
|
80
|
+
/**
|
|
81
|
+
* Everything a person can say about an asset. `create` requires `name`; `update` takes any subset.
|
|
82
|
+
*
|
|
83
|
+
* **No field here carries `.default()`, and that is load-bearing.** `update` is built from
|
|
84
|
+
* `AssetInput.partial()`, and `.partial()` does not strip a default — it only wraps the field in
|
|
85
|
+
* `optional`, so zod still substitutes the default for a key the request never sent. `description`
|
|
86
|
+
* had `.default('')`, so `PATCH {assetId, name}` reached the handler as
|
|
87
|
+
* `{assetId, name, description: ''}`; the service correctly read a present value as "set it" and a
|
|
88
|
+
* rename destroyed the text, writing a bogus `description` diff into `asset_history` as it went.
|
|
89
|
+
* The care the service takes over `undefined` versus `null` is defeated one layer above it, here.
|
|
90
|
+
* A value `create` should fill in belongs on `AssetCreateInput` below, which is never partialled.
|
|
91
|
+
*/
|
|
92
|
+
export declare const AssetInput: z.ZodObject<{
|
|
93
|
+
name: z.ZodString;
|
|
94
|
+
description: z.ZodOptional<z.ZodString>;
|
|
95
|
+
categoryId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
96
|
+
serialNumber: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
97
|
+
location: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
98
|
+
purchasedFrom: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
99
|
+
purchasedOn: z.ZodOptional<z.ZodNullable<z.ZodISODate>>;
|
|
100
|
+
warrantyUntil: z.ZodOptional<z.ZodNullable<z.ZodISODate>>;
|
|
101
|
+
priceMinor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
102
|
+
currency: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
103
|
+
photoFileId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
104
|
+
}, z.core.$strip>;
|
|
105
|
+
export type AssetInput = z.infer<typeof AssetInput>;
|
|
106
|
+
/**
|
|
107
|
+
* What `create` accepts: the same fields, with the one value a new row may not go without.
|
|
108
|
+
*
|
|
109
|
+
* `description` is `not null` in the database, so a create with no description needs *something*.
|
|
110
|
+
* Defaulting it here rather than in `AssetInput` is what keeps `update` able to tell "leave it
|
|
111
|
+
* alone" from "clear it" — see the note above.
|
|
112
|
+
*/
|
|
113
|
+
export declare const AssetCreateInput: z.ZodObject<{
|
|
114
|
+
name: z.ZodString;
|
|
115
|
+
categoryId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
116
|
+
serialNumber: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
117
|
+
location: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
118
|
+
purchasedFrom: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
119
|
+
purchasedOn: z.ZodOptional<z.ZodNullable<z.ZodISODate>>;
|
|
120
|
+
warrantyUntil: z.ZodOptional<z.ZodNullable<z.ZodISODate>>;
|
|
121
|
+
priceMinor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
122
|
+
currency: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
123
|
+
photoFileId: z.ZodOptional<z.ZodNullable<z.ZodUUID>>;
|
|
124
|
+
description: z.ZodDefault<z.ZodString>;
|
|
125
|
+
}, z.core.$strip>;
|
|
126
|
+
export type AssetCreateInput = z.infer<typeof AssetCreateInput>;
|
|
127
|
+
/** What `update` accepts: any subset, and nothing filled in for a key that never arrived. */
|
|
128
|
+
export declare const AssetPatchInput: z.ZodObject<{
|
|
129
|
+
name: z.ZodOptional<z.ZodString>;
|
|
130
|
+
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
131
|
+
categoryId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodUUID>>>;
|
|
132
|
+
serialNumber: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
133
|
+
location: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
134
|
+
purchasedFrom: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
135
|
+
purchasedOn: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodISODate>>>;
|
|
136
|
+
warrantyUntil: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodISODate>>>;
|
|
137
|
+
priceMinor: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
|
|
138
|
+
currency: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
139
|
+
photoFileId: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodUUID>>>;
|
|
140
|
+
}, z.core.$strip>;
|
|
141
|
+
export type AssetPatchInput = z.infer<typeof AssetPatchInput>;
|
|
142
|
+
/** Shared by every workspace-scoped procedure, which is all of them. */
|
|
143
|
+
export declare const ws: z.ZodObject<{
|
|
144
|
+
workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
|
|
145
|
+
}, z.core.$strip>;
|
|
146
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/contract/models.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AAEH,wGAAwG;AACxG,eAAO,MAAM,SAAS,cAAc,CAAA;AAEpC;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;;;;;EAAkF,CAAA;AAC1G,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AAErD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,wCAAoC,CAAA;AAC7D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAA;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,SAAS;;;;EAAqC,CAAA;AAC3D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA;AAEjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;iBAerB,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;iBAE3B,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE/D,6FAA6F;AAC7F,eAAO,MAAM,eAAe;;;;;;;;;;;;iBAAuB,CAAA;AACnD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAE7D,wEAAwE;AACxE,eAAO,MAAM,EAAE;;iBAAyC,CAAA"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { WorkspaceId } from '@kernhq/contracts';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* The nouns this module owns, and the shapes that cross the wire.
|
|
5
|
+
*
|
|
6
|
+
* Imported by **both** halves — the server implements against them, the client calls against them —
|
|
7
|
+
* so nothing here may touch Node. Types only; the procedures live in `router.ts`.
|
|
8
|
+
*/
|
|
9
|
+
/** Lowercase, 2-32 characters. Names the API prefix, the Postgres schema `mod_<id>` and every event. */
|
|
10
|
+
export const MODULE_ID = 'inventory';
|
|
11
|
+
/**
|
|
12
|
+
* An asset's lifecycle. `in_stock` and `assigned` follow custody (an open row in `custody_periods`
|
|
13
|
+
* means assigned); `under_repair` follows an open repair; `reserved` follows a booking that has not
|
|
14
|
+
* been collected; `lost` and `retired` are set by hand when an item stops being usable.
|
|
15
|
+
*
|
|
16
|
+
* Stored rather than derived, because every list filter asks for it — and kept in step inside the
|
|
17
|
+
* same transaction that writes the row it derives from, never by a job afterwards.
|
|
18
|
+
*/
|
|
19
|
+
export const AssetStatus = z.enum(['in_stock', 'assigned', 'reserved', 'under_repair', 'lost', 'retired']);
|
|
20
|
+
/**
|
|
21
|
+
* A value a workspace defined for itself, stored under its `key` in `assets.custom`.
|
|
22
|
+
*
|
|
23
|
+
* `unknown` rather than a union: the field definition says what the type is, and validating a value
|
|
24
|
+
* against a definition the client may not have loaded yet would fail honest input. The server checks
|
|
25
|
+
* it against `field_defs` before writing.
|
|
26
|
+
*/
|
|
27
|
+
export const CustomValues = z.record(z.string(), z.unknown());
|
|
28
|
+
export const Asset = z.object({
|
|
29
|
+
id: z.uuid(),
|
|
30
|
+
workspaceId: WorkspaceId,
|
|
31
|
+
/** Human-facing asset tag (`INV-0001`), assigned by the server, unique per workspace. */
|
|
32
|
+
code: z.string().min(1).max(40),
|
|
33
|
+
name: z.string().min(1).max(200),
|
|
34
|
+
description: z.string().max(4000),
|
|
35
|
+
categoryId: z.uuid().nullable(),
|
|
36
|
+
status: AssetStatus,
|
|
37
|
+
/**
|
|
38
|
+
* The member currently holding the item. A plain uuid — cross-schema foreign keys are what the
|
|
39
|
+
* module boundary exists to prevent — resolved against core membership at read time.
|
|
40
|
+
*/
|
|
41
|
+
custodianUserId: z.uuid().nullable(),
|
|
42
|
+
custodySince: z.string().nullable(),
|
|
43
|
+
serialNumber: z.string().max(200).nullable(),
|
|
44
|
+
location: z.string().max(200).nullable(),
|
|
45
|
+
purchasedOn: z.string().nullable(),
|
|
46
|
+
purchasedFrom: z.string().max(200).nullable(),
|
|
47
|
+
/** Minor units (cents), the convention billing established; formatted on the client. */
|
|
48
|
+
priceMinor: z.number().int().nullable(),
|
|
49
|
+
currency: z.string().length(3).nullable(),
|
|
50
|
+
warrantyUntil: z.string().nullable(),
|
|
51
|
+
photoFileId: z.uuid().nullable(),
|
|
52
|
+
custom: CustomValues,
|
|
53
|
+
createdAt: z.string(),
|
|
54
|
+
updatedAt: z.string(),
|
|
55
|
+
archivedAt: z.string().nullable(),
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* How a list is ordered, and therefore what a page cursor is a bookmark *into*.
|
|
59
|
+
*
|
|
60
|
+
* Exported rather than written inline in `router.ts` because the server validates a cursor against
|
|
61
|
+
* this same list: a bookmark issued under one sort is meaningless under another, and the only way
|
|
62
|
+
* to say so is for both halves to read one enum.
|
|
63
|
+
*/
|
|
64
|
+
export const AssetSort = z.enum(['recent', 'name', 'code']);
|
|
65
|
+
/**
|
|
66
|
+
* Everything a person can say about an asset. `create` requires `name`; `update` takes any subset.
|
|
67
|
+
*
|
|
68
|
+
* **No field here carries `.default()`, and that is load-bearing.** `update` is built from
|
|
69
|
+
* `AssetInput.partial()`, and `.partial()` does not strip a default — it only wraps the field in
|
|
70
|
+
* `optional`, so zod still substitutes the default for a key the request never sent. `description`
|
|
71
|
+
* had `.default('')`, so `PATCH {assetId, name}` reached the handler as
|
|
72
|
+
* `{assetId, name, description: ''}`; the service correctly read a present value as "set it" and a
|
|
73
|
+
* rename destroyed the text, writing a bogus `description` diff into `asset_history` as it went.
|
|
74
|
+
* The care the service takes over `undefined` versus `null` is defeated one layer above it, here.
|
|
75
|
+
* A value `create` should fill in belongs on `AssetCreateInput` below, which is never partialled.
|
|
76
|
+
*/
|
|
77
|
+
export const AssetInput = z.object({
|
|
78
|
+
name: z.string().min(1).max(200),
|
|
79
|
+
description: z.string().max(4000).optional(),
|
|
80
|
+
categoryId: z.uuid().nullish(),
|
|
81
|
+
serialNumber: z.string().max(200).nullish(),
|
|
82
|
+
location: z.string().max(200).nullish(),
|
|
83
|
+
purchasedFrom: z.string().max(200).nullish(),
|
|
84
|
+
purchasedOn: z.iso.date().nullish(),
|
|
85
|
+
warrantyUntil: z.iso.date().nullish(),
|
|
86
|
+
priceMinor: z.number().int().min(0).nullish(),
|
|
87
|
+
currency: z.string().length(3).nullish(),
|
|
88
|
+
photoFileId: z.uuid().nullish(),
|
|
89
|
+
// `custom` is deliberately absent: there is nothing to validate a value against until
|
|
90
|
+
// `fields.*` exists, and accepting arbitrary JSON into a column a workspace has not defined
|
|
91
|
+
// is how a schemaless field bag becomes permanent. It arrives with the field definitions.
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* What `create` accepts: the same fields, with the one value a new row may not go without.
|
|
95
|
+
*
|
|
96
|
+
* `description` is `not null` in the database, so a create with no description needs *something*.
|
|
97
|
+
* Defaulting it here rather than in `AssetInput` is what keeps `update` able to tell "leave it
|
|
98
|
+
* alone" from "clear it" — see the note above.
|
|
99
|
+
*/
|
|
100
|
+
export const AssetCreateInput = AssetInput.extend({
|
|
101
|
+
description: z.string().max(4000).default(''),
|
|
102
|
+
});
|
|
103
|
+
/** What `update` accepts: any subset, and nothing filled in for a key that never arrived. */
|
|
104
|
+
export const AssetPatchInput = AssetInput.partial();
|
|
105
|
+
/** Shared by every workspace-scoped procedure, which is all of them. */
|
|
106
|
+
export const ws = z.object({ workspaceId: WorkspaceId });
|
|
107
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/contract/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<module>.<resource>.<action>`, each with the narrowest scope that works and the roles that hold
|
|
3
|
+
* it by default. A workspace can add or remove any of them afterwards with a custom role.
|
|
4
|
+
*
|
|
5
|
+
* A key with nothing checking it is a role editor full of switches that do nothing, so these arrive
|
|
6
|
+
* with the procedures that enforce them — `custody.manage`, `repair.manage`, `category.manage`,
|
|
7
|
+
* `field.manage`, `value.view` and the stock and purchasing keys with their own phases.
|
|
8
|
+
*/
|
|
9
|
+
export declare const inventoryPermissions: readonly [{
|
|
10
|
+
readonly key: "inventory.asset.view";
|
|
11
|
+
readonly label: "View assets";
|
|
12
|
+
readonly scope: "workspace";
|
|
13
|
+
readonly defaultRoles: ["owner", "admin", "member", "guest"];
|
|
14
|
+
readonly dangerous: false;
|
|
15
|
+
}, {
|
|
16
|
+
readonly key: "inventory.asset.manage";
|
|
17
|
+
readonly label: "Create and edit assets";
|
|
18
|
+
readonly scope: "workspace";
|
|
19
|
+
readonly defaultRoles: ["owner", "admin", "member"];
|
|
20
|
+
readonly dangerous: false;
|
|
21
|
+
}];
|
|
22
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/contract/permissions.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAe/B,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { definePermissions } from '@kernhq/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* `<module>.<resource>.<action>`, each with the narrowest scope that works and the roles that hold
|
|
4
|
+
* it by default. A workspace can add or remove any of them afterwards with a custom role.
|
|
5
|
+
*
|
|
6
|
+
* A key with nothing checking it is a role editor full of switches that do nothing, so these arrive
|
|
7
|
+
* with the procedures that enforce them — `custody.manage`, `repair.manage`, `category.manage`,
|
|
8
|
+
* `field.manage`, `value.view` and the stock and purchasing keys with their own phases.
|
|
9
|
+
*/
|
|
10
|
+
export const inventoryPermissions = definePermissions([
|
|
11
|
+
{
|
|
12
|
+
key: 'inventory.asset.view',
|
|
13
|
+
label: 'View assets',
|
|
14
|
+
scope: 'workspace',
|
|
15
|
+
defaultRoles: ['owner', 'admin', 'member', 'guest'],
|
|
16
|
+
dangerous: false,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
key: 'inventory.asset.manage',
|
|
20
|
+
label: 'Create and edit assets',
|
|
21
|
+
scope: 'workspace',
|
|
22
|
+
defaultRoles: ['owner', 'admin', 'member'],
|
|
23
|
+
dangerous: false,
|
|
24
|
+
},
|
|
25
|
+
]);
|
|
26
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/contract/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;IACpD;QACE,GAAG,EAAE,sBAAsB;QAC3B,KAAK,EAAE,aAAa;QACpB,KAAK,EAAE,WAAW;QAClB,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC;QACnD,SAAS,EAAE,KAAK;KACjB;IACD;QACE,GAAG,EAAE,wBAAwB;QAC7B,KAAK,EAAE,wBAAwB;QAC/B,KAAK,EAAE,WAAW;QAClB,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;QAC1C,SAAS,EAAE,KAAK;KACjB;CACF,CAAC,CAAA"}
|