@kernhq/module-inventory 0.2.0 → 0.4.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 +106 -25
- package/dist/contract/capabilities.d.ts +4 -4
- package/dist/contract/capabilities.d.ts.map +1 -1
- package/dist/contract/capabilities.js +51 -9
- package/dist/contract/capabilities.js.map +1 -1
- package/dist/contract/events.d.ts +43 -0
- package/dist/contract/events.d.ts.map +1 -1
- package/dist/contract/events.js +40 -0
- package/dist/contract/events.js.map +1 -1
- package/dist/contract/index.d.ts +1 -0
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +1 -0
- package/dist/contract/index.js.map +1 -1
- package/dist/contract/models.d.ts +345 -0
- package/dist/contract/models.d.ts.map +1 -1
- package/dist/contract/models.js +245 -0
- package/dist/contract/models.js.map +1 -1
- package/dist/contract/notifications.d.ts +24 -0
- package/dist/contract/notifications.d.ts.map +1 -0
- package/dist/contract/notifications.js +72 -0
- package/dist/contract/notifications.js.map +1 -0
- package/dist/contract/permissions.d.ts +52 -2
- package/dist/contract/permissions.d.ts.map +1 -1
- package/dist/contract/permissions.js +55 -2
- package/dist/contract/permissions.js.map +1 -1
- package/dist/contract/router.d.ts +1108 -0
- package/dist/contract/router.d.ts.map +1 -1
- package/dist/contract/router.js +253 -1
- package/dist/contract/router.js.map +1 -1
- package/dist/contract/settings.d.ts +2 -0
- package/dist/contract/settings.d.ts.map +1 -1
- package/dist/contract/settings.js +24 -4
- package/dist/contract/settings.js.map +1 -1
- package/dist/server/index.d.ts +8 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +289 -5
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs.d.ts +48 -0
- package/dist/server/jobs.d.ts.map +1 -0
- package/dist/server/jobs.js +358 -0
- package/dist/server/jobs.js.map +1 -0
- package/dist/server/router.d.ts +1392 -0
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/router.js +385 -7
- package/dist/server/router.js.map +1 -1
- package/dist/server/schema.d.ts +134 -1
- package/dist/server/schema.d.ts.map +1 -1
- package/dist/server/schema.js +169 -4
- package/dist/server/schema.js.map +1 -1
- package/dist/server/services/assets.d.ts +69 -3
- package/dist/server/services/assets.d.ts.map +1 -1
- package/dist/server/services/assets.js +199 -31
- package/dist/server/services/assets.js.map +1 -1
- package/dist/server/services/attachments.d.ts +80 -0
- package/dist/server/services/attachments.d.ts.map +1 -0
- package/dist/server/services/attachments.js +182 -0
- package/dist/server/services/attachments.js.map +1 -0
- package/dist/server/services/audience.d.ts +15 -0
- package/dist/server/services/audience.d.ts.map +1 -0
- package/dist/server/services/audience.js +64 -0
- package/dist/server/services/audience.js.map +1 -0
- package/dist/server/services/categories.d.ts +157 -0
- package/dist/server/services/categories.d.ts.map +1 -0
- package/dist/server/services/categories.js +309 -0
- package/dist/server/services/categories.js.map +1 -0
- package/dist/server/services/cursor.d.ts +68 -0
- package/dist/server/services/cursor.d.ts.map +1 -0
- package/dist/server/services/cursor.js +39 -0
- package/dist/server/services/cursor.js.map +1 -0
- package/dist/server/services/custody.d.ts +175 -0
- package/dist/server/services/custody.d.ts.map +1 -0
- package/dist/server/services/custody.js +367 -0
- package/dist/server/services/custody.js.map +1 -0
- package/dist/server/services/db-errors.d.ts +7 -0
- package/dist/server/services/db-errors.d.ts.map +1 -0
- package/dist/server/services/db-errors.js +32 -0
- package/dist/server/services/db-errors.js.map +1 -0
- package/dist/server/services/index.d.ts +16 -0
- package/dist/server/services/index.d.ts.map +1 -1
- package/dist/server/services/index.js +25 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/members.d.ts +27 -0
- package/dist/server/services/members.d.ts.map +1 -0
- package/dist/server/services/members.js +39 -0
- package/dist/server/services/members.js.map +1 -0
- package/dist/server/services/notify.d.ts +43 -1
- package/dist/server/services/notify.d.ts.map +1 -1
- package/dist/server/services/notify.js +47 -5
- package/dist/server/services/notify.js.map +1 -1
- package/dist/server/services/offboarding.d.ts +70 -0
- package/dist/server/services/offboarding.d.ts.map +1 -0
- package/dist/server/services/offboarding.js +116 -0
- package/dist/server/services/offboarding.js.map +1 -0
- package/dist/server/services/repairs.d.ts +204 -0
- package/dist/server/services/repairs.d.ts.map +1 -0
- package/dist/server/services/repairs.js +476 -0
- package/dist/server/services/repairs.js.map +1 -0
- package/dist/server/services/search.d.ts +85 -0
- package/dist/server/services/search.d.ts.map +1 -0
- package/dist/server/services/search.js +142 -0
- package/dist/server/services/search.js.map +1 -0
- package/dist/server/services/stats.d.ts +42 -0
- package/dist/server/services/stats.d.ts.map +1 -0
- package/dist/server/services/stats.js +80 -0
- package/dist/server/services/stats.js.map +1 -0
- package/dist/server/services/status.d.ts +102 -0
- package/dist/server/services/status.d.ts.map +1 -0
- package/dist/server/services/status.js +71 -0
- package/dist/server/services/status.js.map +1 -0
- package/migrations/0002_custody_and_categories.sql +23 -0
- package/migrations/0003_repairs.sql +23 -0
- package/migrations/0004_platform_surfaces.sql +51 -0
- package/migrations/0005_repair_dates.sql +35 -0
- package/migrations/0006_workspace_registry_read.sql +50 -0
- package/migrations/0007_history_sequence.sql +83 -0
- package/migrations/0008_category_order_unique.sql +71 -0
- package/migrations/meta/0002_snapshot.json +1054 -0
- package/migrations/meta/0003_snapshot.json +1070 -0
- package/migrations/meta/0004_snapshot.json +1130 -0
- package/migrations/meta/0005_snapshot.json +1135 -0
- package/migrations/meta/_journal.json +49 -0
- package/package.json +2 -1
- package/src/client/api-instance.ts +27 -2
- package/src/client/bidi.test.ts +148 -0
- package/src/client/bidi.ts +85 -0
- package/src/client/components/AssetDetailPanel.svelte +614 -0
- package/src/client/components/AssetFormDialog.svelte +71 -22
- package/src/client/components/AssetPhoto.svelte +178 -0
- package/src/client/components/AttachmentsSection.svelte +327 -0
- package/src/client/components/CustodyDialog.svelte +201 -0
- package/src/client/components/RepairDialog.svelte +271 -0
- package/src/client/components/RepairsSection.svelte +318 -0
- package/src/client/components/Timeline.svelte +347 -0
- package/src/client/components/TimelineText.svelte +124 -0
- package/src/client/core-api.ts +71 -0
- package/src/client/custody.test.ts +31 -0
- package/src/client/custody.ts +34 -0
- package/src/client/errors.test.ts +395 -0
- package/src/client/errors.ts +229 -0
- package/src/client/links.test.ts +74 -0
- package/src/client/links.ts +44 -0
- package/src/client/members.test.ts +132 -0
- package/src/client/members.ts +116 -0
- package/src/client/messages.test.ts +127 -0
- package/src/client/messages.ts +1106 -18
- package/src/client/mock.test.ts +465 -1
- package/src/client/mock.ts +1105 -79
- package/src/client/module.ts +73 -1
- package/src/client/pages/AssetsPage.svelte +317 -45
- package/src/client/permissions.ts +7 -0
- package/src/client/price.test.ts +151 -3
- package/src/client/price.ts +155 -11
- package/src/client/query.ts +36 -0
- package/src/client/reorder.test.ts +100 -0
- package/src/client/reorder.ts +79 -0
- package/src/client/repairs.test.ts +38 -0
- package/src/client/repairs.ts +38 -0
- package/src/client/sequence.test.ts +248 -0
- package/src/client/sequence.ts +185 -0
- package/src/client/settings/CategoriesSettings.svelte +746 -0
- package/src/client/settings/GeneralSettings.svelte +0 -0
- package/src/client/status.ts +29 -0
- package/src/client/timeline.test.ts +175 -0
- package/src/client/timeline.ts +206 -0
- package/src/client/widgets/OverviewWidget.svelte +127 -26
- package/src/client/widgets/RepairsWidget.svelte +124 -0
- package/src/contract/capabilities.ts +53 -9
- package/src/contract/events.ts +49 -0
- package/src/contract/index.ts +1 -0
- package/src/contract/models.ts +270 -0
- package/src/contract/notifications.ts +73 -0
- package/src/contract/permissions.ts +55 -2
- package/src/contract/router.ts +284 -1
- package/src/contract/settings.ts +24 -4
- package/src/module.test.ts +217 -4
- package/src/server/index.ts +311 -4
- package/src/server/inventory.int.test.ts +4109 -19
- package/src/server/jobs.ts +444 -0
- package/src/server/migrations.test.ts +253 -2
- package/src/server/router.ts +486 -6
- package/src/server/schema.ts +171 -3
- package/src/server/services/assets.ts +214 -54
- package/src/server/services/attachments.ts +215 -0
- package/src/server/services/audience.ts +77 -0
- package/src/server/services/categories.ts +337 -0
- package/src/server/services/cursor.ts +104 -0
- package/src/server/services/custody.ts +471 -0
- package/src/server/services/db-errors.ts +42 -0
- package/src/server/services/index.ts +34 -1
- package/src/server/services/members.ts +54 -0
- package/src/server/services/notify.ts +52 -7
- package/src/server/services/offboarding.ts +150 -0
- package/src/server/services/repairs.ts +567 -0
- package/src/server/services/search.ts +166 -0
- package/src/server/services/stats.ts +88 -0
- package/src/server/services/status.test.ts +34 -0
- package/src/server/services/status.ts +143 -0
- package/src/client/settings/core-api.ts +0 -32
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
1
4
|
import { describe, expect, it } from 'vitest'
|
|
2
5
|
import { ar, de, en, fa, inventoryMessageBundles, tr } from './messages.js'
|
|
3
6
|
|
|
@@ -80,6 +83,38 @@ describe('bundles', () => {
|
|
|
80
83
|
}
|
|
81
84
|
})
|
|
82
85
|
|
|
86
|
+
/**
|
|
87
|
+
* The slip that six forms invite: writing five of them and abbreviating the sixth.
|
|
88
|
+
*
|
|
89
|
+
* `many` is the form for 11–99, where Arabic puts the counted noun in the singular accusative —
|
|
90
|
+
* "{n} أصلاً". Because that form is written *differently* from `other`, it gets written from
|
|
91
|
+
* scratch rather than copied, and a compound noun loses half of itself on the way: the shell's
|
|
92
|
+
* `modules_meta_objects` said "{n} نوعاً" — "{n} type" — where every other form said "نوع كائن",
|
|
93
|
+
* "object type". Nothing catches that. It compiles, it has all six categories, it has the right
|
|
94
|
+
* placeholder, and it is missing the word the sentence is about.
|
|
95
|
+
*
|
|
96
|
+
* Word count against `other` is a heuristic and is named as one: a form with *fewer* words than
|
|
97
|
+
* `other` has dropped one, and in a counted phrase the word it drops is the noun. Inflection
|
|
98
|
+
* changes a word's letters, not how many words there are, so this stays true across all six.
|
|
99
|
+
*/
|
|
100
|
+
it('never drops a word from an Arabic plural form that the `other` form has', () => {
|
|
101
|
+
const words = (form: string) => form.split(/\s+/).filter((word) => word && !word.includes('{')).length
|
|
102
|
+
for (const [key, value] of Object.entries(ar)) {
|
|
103
|
+
if (typeof value === 'string') continue
|
|
104
|
+
const other = (value as Record<string, string>).other ?? ''
|
|
105
|
+
for (const [category, form] of Object.entries(value as Record<string, string>)) {
|
|
106
|
+
// `zero` is a negation — "لا أصول" — and is the one form entitled to a different shape.
|
|
107
|
+
if (category === 'zero') continue
|
|
108
|
+
expect({ key, category, form, atLeast: words(other) }).toEqual({
|
|
109
|
+
key,
|
|
110
|
+
category,
|
|
111
|
+
form,
|
|
112
|
+
atLeast: Math.min(words(form), words(other)),
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
83
118
|
it('makes a plural of a key wherever English has one', () => {
|
|
84
119
|
for (const [key, value] of Object.entries(en)) {
|
|
85
120
|
if (typeof value === 'string') continue
|
|
@@ -93,6 +128,71 @@ describe('bundles', () => {
|
|
|
93
128
|
})
|
|
94
129
|
})
|
|
95
130
|
|
|
131
|
+
// ------------------------------------------------------ keys nothing asks for any more
|
|
132
|
+
|
|
133
|
+
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
134
|
+
|
|
135
|
+
/** Everything in this client that could name a key — components included, catalogue excluded. */
|
|
136
|
+
function clientSource(): string {
|
|
137
|
+
const files = readdirSync(HERE, { recursive: true, encoding: 'utf8' }).filter(
|
|
138
|
+
(file) =>
|
|
139
|
+
(file.endsWith('.ts') || file.endsWith('.svelte')) &&
|
|
140
|
+
!file.endsWith('.test.ts') &&
|
|
141
|
+
!file.endsWith('messages.ts'),
|
|
142
|
+
)
|
|
143
|
+
return files.map((file) => readFileSync(join(HERE, file), 'utf8')).join('\n')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The two families of key that are *built* rather than written, and so are never literals.
|
|
148
|
+
*
|
|
149
|
+
* `t(`status_${status}`)` and `actionKey()`'s `history_${action}`. Both lists are duplicated here
|
|
150
|
+
* on purpose — the file is data-only and importing the contract to check a catalogue would be a
|
|
151
|
+
* circular sort of proof — and `status labels` below already holds the first one to the contract.
|
|
152
|
+
*/
|
|
153
|
+
const BUILT = new Set([
|
|
154
|
+
...['in_stock', 'assigned', 'reserved', 'under_repair', 'lost', 'retired'].map((s) => `status_${s}`),
|
|
155
|
+
...[
|
|
156
|
+
'created',
|
|
157
|
+
'updated',
|
|
158
|
+
'assigned',
|
|
159
|
+
'transferred',
|
|
160
|
+
'returned',
|
|
161
|
+
'retired',
|
|
162
|
+
'restored',
|
|
163
|
+
'repair_logged',
|
|
164
|
+
'repair_completed',
|
|
165
|
+
'attachment_added',
|
|
166
|
+
'attachment_removed',
|
|
167
|
+
].map((a) => `history_${a}`),
|
|
168
|
+
])
|
|
169
|
+
|
|
170
|
+
describe('every key is one something asks for', () => {
|
|
171
|
+
/**
|
|
172
|
+
* `inventory.settings_save_error` — "The settings could not be saved" — sat in all five bundles
|
|
173
|
+
* with nothing reading it: the save bar renders `errorMessage(err, t)`, which names the actual
|
|
174
|
+
* refusal instead. A dead key is five translations somebody maintains, reviews and re-reads for
|
|
175
|
+
* a sentence that cannot appear, and nothing about it looks wrong from inside the catalogue.
|
|
176
|
+
*
|
|
177
|
+
* Literals rather than a runtime trace, because a `.svelte` file cannot be unit-tested here —
|
|
178
|
+
* the same reason `errors.test.ts` reads `src/server` off disk. It misses a key that happens to
|
|
179
|
+
* appear as an unrelated string somewhere, which is a false *pass*; it never fails a key that is
|
|
180
|
+
* really used, which is the direction that matters for a check nobody wants to fight.
|
|
181
|
+
*/
|
|
182
|
+
it('has nothing in the catalogue that no screen can reach', () => {
|
|
183
|
+
const source = clientSource()
|
|
184
|
+
const dead = Object.keys(en)
|
|
185
|
+
.map((key) => key.slice('inventory.'.length))
|
|
186
|
+
.filter((name) => !BUILT.has(name))
|
|
187
|
+
.filter((name) => !(source.includes(`'${name}'`) || source.includes(`"${name}"`)))
|
|
188
|
+
expect(dead).toEqual([])
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('is reading the client rather than passing on an empty sweep', () => {
|
|
192
|
+
expect(clientSource().length).toBeGreaterThan(10_000)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
96
196
|
/**
|
|
97
197
|
* Every status the contract can hold has a label, in every language.
|
|
98
198
|
*
|
|
@@ -167,3 +267,30 @@ describe('counted messages', () => {
|
|
|
167
267
|
expect(pick('en', 'inventory.count', 5)).toContain('5')
|
|
168
268
|
})
|
|
169
269
|
})
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* One word per idea, across the whole product and not just across this module.
|
|
273
|
+
*
|
|
274
|
+
* A module is read beside the shell, so a second Turkish word for un-archiving something is a
|
|
275
|
+
* product that says two things for one action. `ws_archive_hint` and `ws_archive_confirm_body` in
|
|
276
|
+
* `shell/messages/tr.json` both say **geri getir** about an archived workspace; this bundle said
|
|
277
|
+
* *geri yükle*, three lines away from "Daha fazla yükle" (load more) and "sayfayı yeniden yükleyin"
|
|
278
|
+
* (reload) — one verb doing three jobs in one panel.
|
|
279
|
+
*
|
|
280
|
+
* Pinned here because it cannot be checked against the shell: a module is built standalone, and
|
|
281
|
+
* `shell/messages/*.json` is not in this package. The word is the decision; the test is the memory.
|
|
282
|
+
*/
|
|
283
|
+
describe('the words Kern already uses', () => {
|
|
284
|
+
it('un-archives with the shell’s own Turkish verb, and never overloads “yükle”', () => {
|
|
285
|
+
expect(tr['inventory.restore']).toBe('Geri getir')
|
|
286
|
+
const overloaded = Object.entries(tr)
|
|
287
|
+
.filter(([, value]) => typeof value === 'string' && (value as string).includes('geri yükle'))
|
|
288
|
+
.map(([key]) => key)
|
|
289
|
+
expect(overloaded).toEqual([])
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
/** «إعادة التحميل» is what the shell calls Reload (`pwa_update_reload`), so a reload says that. */
|
|
293
|
+
it('reloads with the shell’s own words in Arabic', () => {
|
|
294
|
+
expect(ar['inventory.error_conflict']).toContain('أعد تحميل الصفحة')
|
|
295
|
+
})
|
|
296
|
+
})
|