@kernhq/module-inventory 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +134 -9
  2. package/dist/contract/capabilities.d.ts +49 -0
  3. package/dist/contract/capabilities.d.ts.map +1 -0
  4. package/dist/contract/capabilities.js +94 -0
  5. package/dist/contract/capabilities.js.map +1 -0
  6. package/dist/contract/events.d.ts +76 -0
  7. package/dist/contract/events.d.ts.map +1 -0
  8. package/dist/contract/events.js +62 -0
  9. package/dist/contract/events.js.map +1 -0
  10. package/dist/contract/index.d.ts +16 -0
  11. package/dist/contract/index.d.ts.map +1 -0
  12. package/dist/contract/index.js +16 -0
  13. package/dist/contract/index.js.map +1 -0
  14. package/dist/contract/models.d.ts +468 -0
  15. package/dist/contract/models.d.ts.map +1 -0
  16. package/dist/contract/models.js +320 -0
  17. package/dist/contract/models.js.map +1 -0
  18. package/dist/contract/notifications.d.ts +24 -0
  19. package/dist/contract/notifications.d.ts.map +1 -0
  20. package/dist/contract/notifications.js +72 -0
  21. package/dist/contract/notifications.js.map +1 -0
  22. package/dist/contract/permissions.d.ts +72 -0
  23. package/dist/contract/permissions.d.ts.map +1 -0
  24. package/dist/contract/permissions.js +79 -0
  25. package/dist/contract/permissions.js.map +1 -0
  26. package/dist/contract/router.d.ts +1378 -0
  27. package/dist/contract/router.d.ts.map +1 -0
  28. package/dist/contract/router.js +266 -0
  29. package/dist/contract/router.js.map +1 -0
  30. package/dist/contract/settings.d.ts +20 -0
  31. package/dist/contract/settings.d.ts.map +1 -0
  32. package/dist/contract/settings.js +49 -0
  33. package/dist/contract/settings.js.map +1 -0
  34. package/dist/server/index.d.ts +8 -1
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +288 -8
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/jobs.d.ts +48 -0
  39. package/dist/server/jobs.d.ts.map +1 -0
  40. package/dist/server/jobs.js +358 -0
  41. package/dist/server/jobs.js.map +1 -0
  42. package/dist/server/router.d.ts +1789 -0
  43. package/dist/server/router.d.ts.map +1 -0
  44. package/dist/server/router.js +439 -0
  45. package/dist/server/router.js.map +1 -0
  46. package/dist/server/schema.d.ts +156 -9
  47. package/dist/server/schema.d.ts.map +1 -1
  48. package/dist/server/schema.js +183 -11
  49. package/dist/server/schema.js.map +1 -1
  50. package/dist/server/services/assets.d.ts +139 -0
  51. package/dist/server/services/assets.d.ts.map +1 -0
  52. package/dist/server/services/assets.js +429 -0
  53. package/dist/server/services/assets.js.map +1 -0
  54. package/dist/server/services/attachments.d.ts +80 -0
  55. package/dist/server/services/attachments.d.ts.map +1 -0
  56. package/dist/server/services/attachments.js +182 -0
  57. package/dist/server/services/attachments.js.map +1 -0
  58. package/dist/server/services/audience.d.ts +15 -0
  59. package/dist/server/services/audience.d.ts.map +1 -0
  60. package/dist/server/services/audience.js +64 -0
  61. package/dist/server/services/audience.js.map +1 -0
  62. package/dist/server/services/categories.d.ts +57 -0
  63. package/dist/server/services/categories.d.ts.map +1 -0
  64. package/dist/server/services/categories.js +124 -0
  65. package/dist/server/services/categories.js.map +1 -0
  66. package/dist/server/services/cursor.d.ts +68 -0
  67. package/dist/server/services/cursor.d.ts.map +1 -0
  68. package/dist/server/services/cursor.js +39 -0
  69. package/dist/server/services/cursor.js.map +1 -0
  70. package/dist/server/services/custody.d.ts +175 -0
  71. package/dist/server/services/custody.d.ts.map +1 -0
  72. package/dist/server/services/custody.js +367 -0
  73. package/dist/server/services/custody.js.map +1 -0
  74. package/dist/server/services/db-errors.d.ts +7 -0
  75. package/dist/server/services/db-errors.d.ts.map +1 -0
  76. package/dist/server/services/db-errors.js +32 -0
  77. package/dist/server/services/db-errors.js.map +1 -0
  78. package/dist/server/services/index.d.ts +26 -0
  79. package/dist/server/services/index.d.ts.map +1 -0
  80. package/dist/server/services/index.js +39 -0
  81. package/dist/server/services/index.js.map +1 -0
  82. package/dist/server/services/members.d.ts +27 -0
  83. package/dist/server/services/members.d.ts.map +1 -0
  84. package/dist/server/services/members.js +39 -0
  85. package/dist/server/services/members.js.map +1 -0
  86. package/dist/server/services/notify.d.ts +105 -0
  87. package/dist/server/services/notify.d.ts.map +1 -0
  88. package/dist/server/services/notify.js +147 -0
  89. package/dist/server/services/notify.js.map +1 -0
  90. package/dist/server/services/offboarding.d.ts +70 -0
  91. package/dist/server/services/offboarding.d.ts.map +1 -0
  92. package/dist/server/services/offboarding.js +116 -0
  93. package/dist/server/services/offboarding.js.map +1 -0
  94. package/dist/server/services/repairs.d.ts +204 -0
  95. package/dist/server/services/repairs.d.ts.map +1 -0
  96. package/dist/server/services/repairs.js +476 -0
  97. package/dist/server/services/repairs.js.map +1 -0
  98. package/dist/server/services/search.d.ts +85 -0
  99. package/dist/server/services/search.d.ts.map +1 -0
  100. package/dist/server/services/search.js +142 -0
  101. package/dist/server/services/search.js.map +1 -0
  102. package/dist/server/services/stats.d.ts +42 -0
  103. package/dist/server/services/stats.d.ts.map +1 -0
  104. package/dist/server/services/stats.js +80 -0
  105. package/dist/server/services/stats.js.map +1 -0
  106. package/dist/server/services/status.d.ts +102 -0
  107. package/dist/server/services/status.d.ts.map +1 -0
  108. package/dist/server/services/status.js +71 -0
  109. package/dist/server/services/status.js.map +1 -0
  110. package/migrations/0000_init.sql +12 -3
  111. package/migrations/0001_rls.sql +24 -0
  112. package/migrations/0002_custody_and_categories.sql +23 -0
  113. package/migrations/0003_repairs.sql +23 -0
  114. package/migrations/0004_platform_surfaces.sql +51 -0
  115. package/migrations/0005_repair_dates.sql +35 -0
  116. package/migrations/0006_workspace_registry_read.sql +50 -0
  117. package/migrations/0007_history_sequence.sql +83 -0
  118. package/migrations/meta/0000_snapshot.json +40 -13
  119. package/migrations/meta/0002_snapshot.json +1054 -0
  120. package/migrations/meta/0003_snapshot.json +1070 -0
  121. package/migrations/meta/0004_snapshot.json +1130 -0
  122. package/migrations/meta/0005_snapshot.json +1135 -0
  123. package/migrations/meta/_journal.json +44 -2
  124. package/package.json +5 -4
  125. package/src/client/api-instance.ts +27 -2
  126. package/src/client/api.ts +1 -1
  127. package/src/client/bidi.test.ts +148 -0
  128. package/src/client/bidi.ts +85 -0
  129. package/src/client/components/AssetDetailPanel.svelte +614 -0
  130. package/src/client/components/AssetFormDialog.svelte +191 -59
  131. package/src/client/components/AssetPhoto.svelte +178 -0
  132. package/src/client/components/AttachmentsSection.svelte +327 -0
  133. package/src/client/components/CustodyDialog.svelte +201 -0
  134. package/src/client/components/RepairDialog.svelte +271 -0
  135. package/src/client/components/RepairsSection.svelte +318 -0
  136. package/src/client/components/Timeline.svelte +347 -0
  137. package/src/client/components/TimelineText.svelte +124 -0
  138. package/src/client/core-api.ts +71 -0
  139. package/src/client/custody.test.ts +31 -0
  140. package/src/client/custody.ts +34 -0
  141. package/src/client/errors.test.ts +365 -0
  142. package/src/client/errors.ts +201 -0
  143. package/src/client/i18n.ts +11 -166
  144. package/src/client/index.ts +8 -1
  145. package/src/client/links.test.ts +74 -0
  146. package/src/client/links.ts +44 -0
  147. package/src/client/members.test.ts +132 -0
  148. package/src/client/members.ts +116 -0
  149. package/src/client/messages.test.ts +296 -0
  150. package/src/client/messages.ts +1424 -0
  151. package/src/client/mock.test.ts +555 -0
  152. package/src/client/mock.ts +1261 -52
  153. package/src/client/module.ts +76 -2
  154. package/src/client/pages/AssetsPage.svelte +638 -145
  155. package/src/client/permissions.ts +8 -1
  156. package/src/client/price.test.ts +254 -0
  157. package/src/client/price.ts +279 -0
  158. package/src/client/query.test.ts +58 -0
  159. package/src/client/query.ts +51 -2
  160. package/src/client/repairs.test.ts +38 -0
  161. package/src/client/repairs.ts +38 -0
  162. package/src/client/settings/CategoriesSettings.svelte +421 -0
  163. package/src/client/settings/GeneralSettings.svelte +403 -0
  164. package/src/client/status.ts +29 -0
  165. package/src/client/timeline.test.ts +175 -0
  166. package/src/client/timeline.ts +206 -0
  167. package/src/client/widgets/OverviewWidget.svelte +140 -26
  168. package/src/client/widgets/RepairsWidget.svelte +124 -0
  169. package/src/contract/capabilities.ts +99 -0
  170. package/src/contract/events.ts +83 -0
  171. package/src/contract/index.ts +16 -0
  172. package/src/contract/models.ts +360 -0
  173. package/src/contract/notifications.ts +73 -0
  174. package/src/contract/permissions.ts +79 -0
  175. package/src/contract/router.ts +300 -0
  176. package/src/contract/settings.ts +50 -0
  177. package/src/module.test.ts +330 -7
  178. package/src/server/index.ts +318 -8
  179. package/src/server/inventory.int.test.ts +4374 -0
  180. package/src/server/jobs.ts +444 -0
  181. package/src/server/migrations.test.ts +251 -0
  182. package/src/server/router.ts +574 -0
  183. package/src/server/schema.ts +184 -10
  184. package/src/server/services/assets.ts +528 -0
  185. package/src/server/services/attachments.ts +215 -0
  186. package/src/server/services/audience.ts +77 -0
  187. package/src/server/services/categories.ts +136 -0
  188. package/src/server/services/cursor.ts +104 -0
  189. package/src/server/services/custody.ts +471 -0
  190. package/src/server/services/db-errors.ts +42 -0
  191. package/src/server/services/index.ts +56 -0
  192. package/src/server/services/members.ts +54 -0
  193. package/src/server/services/notify.ts +196 -0
  194. package/src/server/services/offboarding.ts +150 -0
  195. package/src/server/services/repairs.ts +567 -0
  196. package/src/server/services/search.ts +166 -0
  197. package/src/server/services/stats.ts +88 -0
  198. package/src/server/services/status.test.ts +34 -0
  199. package/src/server/services/status.ts +143 -0
  200. package/tsconfig.base.json +22 -0
  201. package/tsconfig.client.json +1 -1
  202. package/tsconfig.json +1 -1
  203. package/vitest.config.ts +18 -3
  204. package/dist/contract.d.ts +0 -387
  205. package/dist/contract.d.ts.map +0 -1
  206. package/dist/contract.js +0 -119
  207. package/dist/contract.js.map +0 -1
  208. package/dist/server/_impl.d.ts +0 -427
  209. package/dist/server/_impl.d.ts.map +0 -1
  210. package/dist/server/_impl.js +0 -204
  211. package/dist/server/_impl.js.map +0 -1
  212. package/src/contract.ts +0 -143
  213. package/src/server/_impl.ts +0 -275
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/contract/router.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA0BvB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqC1B;;;;;;;;;;WAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAOL;;;;;;;OAOG;;QAED,6FAA6F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAK7F,6EAA6E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAK7E;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAKH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAKH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAOL;;;;;OAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAcD;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAOL;;;;;;;;;;OAUG;;QAED;;;;;;;;;;WAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAYH;;;;;;;WAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAKH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAKH;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAcL;;;;;;;;;;OAUG;;QAED;;;;;;WAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAKH,oGAAoG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWpG,iGAAiG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAOnG;;;;;;;;;OASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIJ,CAAA;AACD,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAA"}
@@ -0,0 +1,266 @@
1
+ import { baseContract, PageInput, page } from '@kernhq/contracts';
2
+ import { z } from 'zod';
3
+ import { Asset, AssetCreateInput, AssetHistoryEntry, AssetPatchInput, AssetSort, AssetStatus, Attachment, Category, CategoryInput, CustodyPeriod, CustodyResult, InventoryStats, RepairInput, RepairListItem, RepairPatchInput, RepairResult, ws, } from './models.js';
4
+ const t = ['inventory'];
5
+ /** A handover note is optional everywhere and shaped the same everywhere. */
6
+ const custodyNote = z.string().max(500).nullish();
7
+ export const inventoryContract = {
8
+ assets: {
9
+ list: baseContract
10
+ .route({ method: 'GET', path: '/assets', tags: t })
11
+ .input(ws.extend({
12
+ ...PageInput.shape,
13
+ q: z.string().max(200).optional(),
14
+ categoryId: z.uuid().optional(),
15
+ status: AssetStatus.optional(),
16
+ custodianUserId: z.uuid().optional(),
17
+ /**
18
+ * Archived rows are excluded unless asked for. The page used to filter them in the
19
+ * browser, which is wrong the moment there is more than one page of them: the first
20
+ * twenty rows come back, half are dropped, and the list looks short rather than paged.
21
+ */
22
+ archived: z.boolean().default(false),
23
+ sort: AssetSort.default('recent'),
24
+ }))
25
+ .output(page(Asset)),
26
+ get: baseContract
27
+ .route({ method: 'GET', path: '/assets/{assetId}', tags: t })
28
+ .input(ws.extend({ assetId: z.uuid() }))
29
+ .output(Asset),
30
+ create: baseContract
31
+ .route({ method: 'POST', path: '/assets', tags: t })
32
+ .input(ws.extend(AssetCreateInput.shape))
33
+ .output(Asset),
34
+ update: baseContract
35
+ .route({ method: 'PATCH', path: '/assets/{assetId}', tags: t })
36
+ .input(ws.extend({ assetId: z.uuid(), ...AssetPatchInput.shape }))
37
+ .output(Asset),
38
+ archive: baseContract
39
+ .route({ method: 'POST', path: '/assets/{assetId}/archive', tags: t })
40
+ .input(ws.extend({ assetId: z.uuid(), archived: z.boolean().default(true) }))
41
+ .output(Asset),
42
+ /**
43
+ * The asset's own timeline, newest first.
44
+ *
45
+ * Paged with the same keyset discipline `assets.list` uses and the same cursor codec, because a
46
+ * second bookmark format is a second set of the three bugs the first one had. The bookmark is a
47
+ * row id; the ordering is by id, which for a uuidv7 is the clock and, unlike `created_at`, is
48
+ * unique — two entries written in one transaction (a create and its first custody row) share a
49
+ * timestamp and a page boundary between them would repeat or drop one.
50
+ *
51
+ * Reads on `inventory.asset.view`. See `permissions.ts` for why custody is not gated separately.
52
+ */
53
+ history: baseContract
54
+ .route({ method: 'GET', path: '/assets/{assetId}/history', tags: t })
55
+ .input(ws.extend({ assetId: z.uuid(), ...PageInput.shape }))
56
+ .output(page(AssetHistoryEntry)),
57
+ },
58
+ /**
59
+ * Who is holding what.
60
+ *
61
+ * Four verbs rather than one, because "hand it to somebody" and "hand it on to somebody else" are
62
+ * different questions with different failure modes: assigning something already out is a mistake
63
+ * worth refusing, and transferring something nobody holds is a different mistake. One procedure
64
+ * taking `userId | null` would answer both by silently doing whatever the row happened to allow.
65
+ */
66
+ custody: {
67
+ /** Hand a free item to a member. Refuses if somebody already has it — that is `transfer`. */
68
+ assign: baseContract
69
+ .route({ method: 'POST', path: '/assets/{assetId}/custody', tags: t })
70
+ .input(ws.extend({ assetId: z.uuid(), userId: z.uuid(), note: custodyNote }))
71
+ .output(CustodyResult),
72
+ /** Take it back. Closes the open period and puts the asset back in stock. */
73
+ return: baseContract
74
+ .route({ method: 'POST', path: '/assets/{assetId}/custody/return', tags: t })
75
+ .input(ws.extend({ assetId: z.uuid(), note: custodyNote }))
76
+ .output(CustodyResult),
77
+ /**
78
+ * Hand it straight on: one transaction, not a return followed by an assign.
79
+ *
80
+ * Two calls would leave the asset `in_stock` with no custodian in between — visible to anybody
81
+ * reading the list at that moment, and permanently visible in the timeline as a return that
82
+ * nobody performed.
83
+ */
84
+ transfer: baseContract
85
+ .route({ method: 'POST', path: '/assets/{assetId}/custody/transfer', tags: t })
86
+ .input(ws.extend({ assetId: z.uuid(), userId: z.uuid(), note: custodyNote }))
87
+ .output(CustodyResult),
88
+ /**
89
+ * Every period for one asset, newest first — "who had this laptop before me".
90
+ *
91
+ * An array rather than a page, like HR's `employment.history`: the rows are bounded by how many
92
+ * times one item changed hands, which is tens over its life. `limit` caps it rather than
93
+ * paging, so the answer is never unbounded and the caller never has a cursor to keep.
94
+ */
95
+ history: baseContract
96
+ .route({ method: 'GET', path: '/assets/{assetId}/custody', tags: t })
97
+ .input(ws.extend({ assetId: z.uuid(), limit: z.number().int().min(1).max(200).default(100) }))
98
+ .output(z.array(CustodyPeriod)),
99
+ /**
100
+ * What one person is holding right now.
101
+ *
102
+ * Answered from `assets.custodian_user_id` — denormalised inside the same transaction that
103
+ * writes the period, and indexed — rather than from an open-period join, so the offboarding
104
+ * question ("what does Ada still have?") is one indexed read.
105
+ */
106
+ byUser: baseContract
107
+ .route({ method: 'GET', path: '/custody/by-user/{userId}', tags: t })
108
+ .input(ws.extend({ userId: z.uuid(), ...PageInput.shape }))
109
+ .output(page(Asset)),
110
+ },
111
+ /**
112
+ * How a workspace groups what it owns.
113
+ *
114
+ * Not paged: a workspace has tens of categories, and every one of them has to be in the picker
115
+ * anyway. A cursor here would be a page boundary in a dropdown.
116
+ */
117
+ categories: {
118
+ list: baseContract
119
+ .route({ method: 'GET', path: '/categories', tags: t })
120
+ .input(ws.extend({ archived: z.boolean().default(false) }))
121
+ .output(z.array(Category)),
122
+ create: baseContract
123
+ .route({ method: 'POST', path: '/categories', tags: t })
124
+ .input(ws.extend(CategoryInput.shape))
125
+ .output(Category),
126
+ update: baseContract
127
+ .route({ method: 'PATCH', path: '/categories/{categoryId}', tags: t })
128
+ .input(ws.extend({ categoryId: z.uuid(), ...CategoryInput.partial().shape }))
129
+ .output(Category),
130
+ /**
131
+ * Archive, not delete — and the same procedure restores.
132
+ *
133
+ * `assets.category_id` carries no foreign key, so a delete would leave every asset filed under
134
+ * it pointing at nothing: a blank column, and a timeline entry that recorded the move losing
135
+ * the name it recorded. Archiving is reversible and destroys nothing.
136
+ */
137
+ archive: baseContract
138
+ .route({ method: 'POST', path: '/categories/{categoryId}/archive', tags: t })
139
+ .input(ws.extend({ categoryId: z.uuid(), archived: z.boolean().default(true) }))
140
+ .output(Category),
141
+ },
142
+ /**
143
+ * What went away to be fixed.
144
+ *
145
+ * **Behind the `repairs` capability**, which is this module's first switchable one — so every
146
+ * procedure here answers **404** rather than 403 in a workspace that has it off. 403 would say
147
+ * "this exists and you may not have it", which is false for a company that does not record
148
+ * repairs, and it would contradict a panel that has already hidden the tab.
149
+ *
150
+ * Writing takes `inventory.repair.manage`; reading rides `inventory.asset.view`, for the reason
151
+ * custody does — "where is the projector" is the question the register exists to answer.
152
+ */
153
+ repairs: {
154
+ /**
155
+ * One asset's repairs, or the whole workspace's — the same procedure, because they are the same
156
+ * query with one filter and a second one would be a second thing to keep in step.
157
+ *
158
+ * `open: true` is the "what is away right now" question a dashboard card asks, and it is a
159
+ * filter rather than a procedure of its own for the same reason.
160
+ *
161
+ * Paged, unlike `custody.history`: one asset's repairs are bounded by how often it breaks, but
162
+ * a workspace's are not. Ordered newest-logged first, by row id — a uuidv7 already carries the
163
+ * clock and is unique, where `sent_on` is a date two repairs logged the same day share.
164
+ */
165
+ list: baseContract
166
+ .route({ method: 'GET', path: '/repairs', tags: t })
167
+ .input(ws.extend({
168
+ ...PageInput.shape,
169
+ assetId: z.uuid().optional(),
170
+ /** `true` for still away, `false` for finished, absent for both. */
171
+ open: z.boolean().optional(),
172
+ }))
173
+ .output(page(RepairListItem)),
174
+ /**
175
+ * Send it away. Refuses when the item is already at a repairer — one open repair per asset, and
176
+ * `inventory_repairs_one_open_uq` is what makes that true in the database rather than merely
177
+ * likely in the service.
178
+ *
179
+ * `sentOn` is optional and defaults to today **on the server**: a browser clock is not a fact
180
+ * this module is willing to record, and the same reasoning already keeps asset tags server-side.
181
+ */
182
+ create: baseContract
183
+ .route({ method: 'POST', path: '/assets/{assetId}/repairs', tags: t })
184
+ .input(ws.extend({ assetId: z.uuid(), ...RepairInput.shape }))
185
+ .output(RepairResult),
186
+ /**
187
+ * Correct what was recorded — a vendor, a cost that arrived with the invoice a week later.
188
+ *
189
+ * Deliberately cannot set `returnedOn`: that one column decides whether the asset reads as
190
+ * `under_repair`, so exactly one procedure moves it and the derived status has one door rather
191
+ * than two.
192
+ */
193
+ update: baseContract
194
+ .route({ method: 'PATCH', path: '/repairs/{repairId}', tags: t })
195
+ .input(ws.extend({ repairId: z.uuid(), ...RepairPatchInput.shape }))
196
+ .output(RepairResult),
197
+ /**
198
+ * It came back. Closes the repair and puts the asset back to `assigned` if somebody still holds
199
+ * it, or `in_stock` if nobody does — never blindly to `in_stock`, which would quietly release
200
+ * whoever is answerable for it.
201
+ *
202
+ * Takes the cost, because that is when the invoice usually arrives.
203
+ */
204
+ complete: baseContract
205
+ .route({ method: 'POST', path: '/repairs/{repairId}/complete', tags: t })
206
+ .input(ws.extend({
207
+ repairId: z.uuid(),
208
+ returnedOn: z.iso.date().optional(),
209
+ costMinor: z.number().int().min(0).nullish(),
210
+ currency: z.string().length(3).nullish(),
211
+ }))
212
+ .output(RepairResult),
213
+ },
214
+ /**
215
+ * Receipts, warranties, manuals — and the asset's photo, which is an `Asset` field rather than one
216
+ * of these.
217
+ *
218
+ * **Behind the `attachments` capability**, so these answer 404 in a workspace that has it off.
219
+ *
220
+ * **A module does not upload.** The browser sends the bytes to core's file service and hands this
221
+ * module the id core gave it; `add` records that this asset has that file. Nothing here streams,
222
+ * signs or stores anything, and `remove` detaches rather than deleting core's file — the same
223
+ * bytes may be attached elsewhere, and a module has no standing to destroy another module's row.
224
+ */
225
+ attachments: {
226
+ /**
227
+ * Every file on one asset, its repairs' included, each carrying its own `repairId`.
228
+ *
229
+ * Not paged and not filtered by repair: one asset's files are bounded and entirely loaded, so
230
+ * the panel groups them in the browser. That is the one case where filtering client-side is
231
+ * right, and it is the opposite of what `assets.list` may do.
232
+ */
233
+ list: baseContract
234
+ .route({ method: 'GET', path: '/assets/{assetId}/attachments', tags: t })
235
+ .input(ws.extend({ assetId: z.uuid() }))
236
+ .output(z.array(Attachment)),
237
+ /** Attach files core already holds. `repairId` files them under one repair instead of the asset. */
238
+ add: baseContract
239
+ .route({ method: 'POST', path: '/assets/{assetId}/attachments', tags: t })
240
+ .input(ws.extend({
241
+ assetId: z.uuid(),
242
+ fileIds: z.array(z.uuid()).min(1).max(20),
243
+ repairId: z.uuid().nullish(),
244
+ }))
245
+ .output(z.array(Attachment)),
246
+ /** Answers with the id it detached, so a client can drop exactly that row without re-reading. */
247
+ remove: baseContract
248
+ .route({ method: 'DELETE', path: '/attachments/{attachmentId}', tags: t })
249
+ .input(ws.extend({ attachmentId: z.uuid() }))
250
+ .output(z.object({ id: z.uuid() })),
251
+ },
252
+ /**
253
+ * The register in numbers.
254
+ *
255
+ * One procedure rather than a `total` on `assets.list`, because they answer different questions:
256
+ * a list's total describes the filter you asked for, and this describes the workspace. The assets
257
+ * page needs both — "showing 50 of 214" is two numbers from two places.
258
+ *
259
+ * Not behind a capability: it counts assets, which is `core`. `outForRepair` comes back null
260
+ * rather than 0 where `repairs` is off — see `InventoryStats`.
261
+ */
262
+ stats: {
263
+ summary: baseContract.route({ method: 'GET', path: '/stats', tags: t }).input(ws).output(InventoryStats),
264
+ },
265
+ };
266
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/contract/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EACL,KAAK,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,WAAW,EACX,UAAU,EACV,QAAQ,EACR,aAAa,EACb,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,EAAE,GACH,MAAM,aAAa,CAAA;AAEpB,MAAM,CAAC,GAAG,CAAC,WAAW,CAAU,CAAA;AAEhC,6EAA6E;AAC7E,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAA;AAEjD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE;QACN,IAAI,EAAE,YAAY;aACf,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAClD,KAAK,CACJ,EAAE,CAAC,MAAM,CAAC;YACR,GAAG,SAAS,CAAC,KAAK;YAClB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;YACjC,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;YAC/B,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE;YAC9B,eAAe,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;YACpC;;;;eAIG;YACH,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;YACpC,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC;SAClC,CAAC,CACH;aACA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,GAAG,EAAE,YAAY;aACd,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAC5D,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;aACvC,MAAM,CAAC,KAAK,CAAC;QAChB,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACnD,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;aACxC,MAAM,CAAC,KAAK,CAAC;QAChB,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAC9D,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC;aACjE,MAAM,CAAC,KAAK,CAAC;QAChB,OAAO,EAAE,YAAY;aAClB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACrE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC5E,MAAM,CAAC,KAAK,CAAC;QAChB;;;;;;;;;;WAUG;QACH,OAAO,EAAE,YAAY;aAClB,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACpE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;aAC3D,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;KACnC;IAED;;;;;;;OAOG;IACH,OAAO,EAAE;QACP,6FAA6F;QAC7F,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACrE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;aAC5E,MAAM,CAAC,aAAa,CAAC;QACxB,6EAA6E;QAC7E,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kCAAkC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAC5E,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;aAC1D,MAAM,CAAC,aAAa,CAAC;QACxB;;;;;;WAMG;QACH,QAAQ,EAAE,YAAY;aACnB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,oCAAoC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAC9E,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;aAC5E,MAAM,CAAC,aAAa,CAAC;QACxB;;;;;;WAMG;QACH,OAAO,EAAE,YAAY;aAClB,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACpE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aAC7F,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACjC;;;;;;WAMG;QACH,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACpE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;aAC1D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KACvB;IAED;;;;;OAKG;IACH,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;aACf,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACtD,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;aAC1D,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACvD,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;aACrC,MAAM,CAAC,QAAQ,CAAC;QACnB,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACrE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;aAC5E,MAAM,CAAC,QAAQ,CAAC;QACnB;;;;;;WAMG;QACH,OAAO,EAAE,YAAY;aAClB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kCAAkC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAC5E,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC/E,MAAM,CAAC,QAAQ,CAAC;KACpB;IAED;;;;;;;;;;OAUG;IACH,OAAO,EAAE;QACP;;;;;;;;;;WAUG;QACH,IAAI,EAAE,YAAY;aACf,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACnD,KAAK,CACJ,EAAE,CAAC,MAAM,CAAC;YACR,GAAG,SAAS,CAAC,KAAK;YAClB,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;YAC5B,oEAAoE;YACpE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;SAC7B,CAAC,CACH;aACA,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/B;;;;;;;WAOG;QACH,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACrE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC;aAC7D,MAAM,CAAC,YAAY,CAAC;QACvB;;;;;;WAMG;QACH,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAChE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC;aACnE,MAAM,CAAC,YAAY,CAAC;QACvB;;;;;;WAMG;QACH,QAAQ,EAAE,YAAY;aACnB,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACxE,KAAK,CACJ,EAAE,CAAC,MAAM,CAAC;YACR,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE;YAClB,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;YACnC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;YAC5C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;SACzC,CAAC,CACH;aACA,MAAM,CAAC,YAAY,CAAC;KACxB;IAED;;;;;;;;;;OAUG;IACH,WAAW,EAAE;QACX;;;;;;WAMG;QACH,IAAI,EAAE,YAAY;aACf,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,+BAA+B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACxE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;aACvC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,oGAAoG;QACpG,GAAG,EAAE,YAAY;aACd,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACzE,KAAK,CACJ,EAAE,CAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;YACjB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE;SAC7B,CAAC,CACH;aACA,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,iGAAiG;QACjG,MAAM,EAAE,YAAY;aACjB,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,6BAA6B,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACzE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;aAC5C,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;KACtC;IAED;;;;;;;;;OASG;IACH,KAAK,EAAE;QACL,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC;KACzG;CACF,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Workspace-level settings for Inventory.
4
+ *
5
+ * Deliberately small. Nearly everything an administrator configures belongs to a category, a
6
+ * location or a field definition, because those are the things that differ between two kinds of
7
+ * item in the same company. What is left is genuinely workspace-wide.
8
+ *
9
+ * Note what is *not* here: the capability switches. Those live under a reserved `$capabilities` key
10
+ * the platform owns, so turning one off cannot collide with a settings field and cannot be dropped
11
+ * by a settings round-trip.
12
+ */
13
+ export declare const InventorySettings: z.ZodObject<{
14
+ assetCodePrefix: z.ZodDefault<z.ZodString>;
15
+ assetCodePad: z.ZodDefault<z.ZodNumber>;
16
+ warrantyNoticeDays: z.ZodDefault<z.ZodNumber>;
17
+ repairOverdueDays: z.ZodDefault<z.ZodNumber>;
18
+ }, z.core.$strip>;
19
+ export type InventorySettings = z.infer<typeof InventorySettings>;
20
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/contract/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB;;;;;iBAmC5B,CAAA;AACF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Workspace-level settings for Inventory.
4
+ *
5
+ * Deliberately small. Nearly everything an administrator configures belongs to a category, a
6
+ * location or a field definition, because those are the things that differ between two kinds of
7
+ * item in the same company. What is left is genuinely workspace-wide.
8
+ *
9
+ * Note what is *not* here: the capability switches. Those live under a reserved `$capabilities` key
10
+ * the platform owns, so turning one off cannot collide with a settings field and cannot be dropped
11
+ * by a settings round-trip.
12
+ */
13
+ export const InventorySettings = z.object({
14
+ /**
15
+ * What an asset tag looks like. `INV-` and 4 gives `INV-0042`.
16
+ *
17
+ * People read these off a sticker and say them out loud, so a workspace that already labels its
18
+ * laptops `LT-` should not have to keep two numbering systems in its head. The counter itself is a
19
+ * row in `mod_inventory.counters`, not a setting — a number an administrator can edit is a number
20
+ * that produces a duplicate tag.
21
+ */
22
+ assetCodePrefix: z.string().max(8).default('INV-'),
23
+ assetCodePad: z.number().int().min(1).max(10).default(4),
24
+ /**
25
+ * How far ahead of a warranty running out somebody is told.
26
+ *
27
+ * This spent a release describing a sweep that did not exist — no job, no subscription, nothing
28
+ * reading the number — and was taken out for it. It is back because `warranty-sweep` reads it
29
+ * every morning: a live asset whose `warranty_until` falls inside this many days earns exactly
30
+ * one notice, marked on the row so the next morning does not send it again.
31
+ *
32
+ * A month by default, which is about how long it takes to decide whether to extend a warranty or
33
+ * budget for a replacement. Capped at a year: further out than that is not a notice, it is a
34
+ * report.
35
+ */
36
+ warrantyNoticeDays: z.number().int().min(1).max(365).default(30),
37
+ /**
38
+ * How long an item may be at a repairer before somebody is asked to chase it.
39
+ *
40
+ * Read by `repair-overdue`, which tells the person who logged the repair — and whoever is still
41
+ * holding the item — once, and then leaves them alone. Two weeks by default: long enough that an
42
+ * ordinary screen replacement never trips it, short enough that a laptop nobody chased does.
43
+ *
44
+ * A workspace with the `repairs` capability off never meets this: the sweep asks first, and a
45
+ * setting whose feature is switched off changes nothing rather than firing quietly.
46
+ */
47
+ repairOverdueDays: z.number().int().min(1).max(365).default(14),
48
+ });
49
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/contract/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC;;;;;;;OAOG;IACH,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAClD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD;;;;;;;;;;;OAWG;IACH,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAChE;;;;;;;;;OASG;IACH,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAChE,CAAC,CAAA"}
@@ -1,3 +1,10 @@
1
- export declare const inventoryModule: import("@kernhq/kernel").ServerModule<import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
1
+ import { z } from 'zod';
2
+ export declare const inventoryModule: import("@kernhq/kernel").ServerModule<z.ZodObject<{
3
+ assetCodePrefix: z.ZodDefault<z.ZodString>;
4
+ assetCodePad: z.ZodDefault<z.ZodNumber>;
5
+ warrantyNoticeDays: z.ZodDefault<z.ZodNumber>;
6
+ repairOverdueDays: z.ZodDefault<z.ZodNumber>;
7
+ }, z.core.$strip>>;
2
8
  export default inventoryModule;
9
+ export type InventoryModule = typeof inventoryModule;
3
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,eAAe,2IAyB1B,CAAA;AACF,eAAe,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA8CvB,eAAO,MAAM,eAAe;;;;;kBAiR1B,CAAA;AAgBF,eAAe,eAAe,CAAA;AAC9B,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAA"}