@cosmicdrift/kumiko-testing 0.386.0 → 0.387.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/LICENSE CHANGED
@@ -1,57 +1,21 @@
1
- Business Source License 1.1
2
-
3
- Parameters
4
-
5
- Licensor: Marc Frost
6
-
7
- Licensed Work: @cosmicdrift/kumiko-testing
8
- The Licensed Work is © 2026 Marc Frost.
9
-
10
- Additional Use Grant:
11
- You may use the Licensed Work in production for any purpose, including
12
- commercially, EXCEPT for the Restricted Use.
13
-
14
- "Restricted Use" is defined as using the Licensed Work to provide a platform
15
- or service to third parties that allows them to host, deploy, or run their
16
- own applications built with the Licensed Work. This includes, but is not
17
- limited to: managed hosting services, software-as-a-service (SaaS) platforms,
18
- platform-as-a-service (PaaS), developer platforms, or any multi-tenant
19
- managed offering of the Licensed Work.
20
-
21
- This restriction does not apply to the Licensor, any entity controlled by,
22
- controlling, or under common control with the Licensor ("Affiliates"), or
23
- contractors acting on their behalf. The Licensor remains free to use the
24
- Licensed Work for any purpose, including for the operation of kumiko.rocks.
25
-
26
- Change Date: 2030-05-05
27
- Change License: Apache License, Version 2.0
28
-
29
-
30
- Terms
31
-
32
- The Licensor hereby grants you the right to copy, modify, create derivative works,
33
- redistribute, and make non-production use of the Licensed Work. The Licensor may
34
- make an Additional Use Grant, above, permitting limited production use.
35
-
36
- Effective on the Change Date, or the fourth anniversary of the first publicly
37
- available distribution of the Licensed Work under this License, whichever comes
38
- first, this License will convert to the Change License.
39
-
40
- This Business Source License governs use of the Licensed Work in all cases, except
41
- as to any use that is explicitly granted in the Additional Use Grant above or
42
- under the Change License after the Change Date.
43
-
44
- If your use of the Licensed Work does not comply with the requirements of this
45
- License, you must cease use of the Licensed Work immediately.
46
-
47
- All copies of the Licensed Work, and all derivative works thereof, must include
48
- this License.
49
-
50
- This License does not grant you any right, title, or interest in any trademark,
51
- logo, or branding of the Licensor, except as required to comply with this License.
52
-
53
- TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
54
- “AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
55
- WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
56
- TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
57
- ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marc Frost
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-testing",
3
- "version": "0.386.0",
3
+ "version": "0.387.0",
4
4
  "description": "Test template for Kumiko apps: per-flow seedTenant, app test stack, canonical test preloads, bunfig generator and integration runner.",
5
- "license": "BUSL-1.1",
5
+ "license": "MIT",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
7
7
  "repository": {
8
8
  "type": "git",
@@ -99,9 +99,9 @@
99
99
  "kumiko-testing": "./bin/kumiko-testing.ts"
100
100
  },
101
101
  "dependencies": {
102
- "@cosmicdrift/kumiko-framework": "0.386.0",
103
- "@cosmicdrift/kumiko-guards": "0.386.0",
104
- "@cosmicdrift/kumiko-types": "0.386.0",
102
+ "@cosmicdrift/kumiko-framework": "0.387.0",
103
+ "@cosmicdrift/kumiko-guards": "0.387.0",
104
+ "@cosmicdrift/kumiko-types": "0.387.0",
105
105
  "zod": "^4.4.3"
106
106
  },
107
107
  "peerDependencies": {
@@ -125,8 +125,8 @@
125
125
  }
126
126
  },
127
127
  "devDependencies": {
128
- "@cosmicdrift/kumiko-bundled-features": "0.386.0",
129
- "@cosmicdrift/kumiko-dev-server": "0.386.0",
128
+ "@cosmicdrift/kumiko-bundled-features": "0.387.0",
129
+ "@cosmicdrift/kumiko-dev-server": "0.387.0",
130
130
  "@happy-dom/global-registrator": "^20.11.2",
131
131
  "@playwright/test": "^1.62.1",
132
132
  "@testing-library/dom": "^10.4.1",
package/src/bunfig.ts CHANGED
@@ -102,7 +102,7 @@ type BunfigBlock = { readonly header: string; readonly lines: readonly string[]
102
102
  // contain "[" are never alone on their own line. Anything before the first
103
103
  // header (top-level keys like `preload`/`telemetry`/`smol`/`logLevel`, plus
104
104
  // the header comments) is its own block under the synthetic header "" —
105
- // dropping it silently lost those keys (kumiko-framework#3120).
105
+ // dropping it silently lost those keys.
106
106
  function splitBunfigBlocks(content: string): readonly BunfigBlock[] {
107
107
  const blocks: { header: string; lines: string[] }[] = [];
108
108
  let current: { header: string; lines: string[] } = { header: "", lines: [] };
@@ -224,7 +224,7 @@ function appendArrayExtras(
224
224
  * verbatim, appended after the generated content — so a section the
225
225
  * template doesn't own this run is never silently dropped. A key inside a
226
226
  * section the template DOES emit that isn't in this run's own version of
227
- * that section (e.g. `concurrency`, `timeout`, kumiko-framework#3120) fails
227
+ * that section (e.g. `concurrency`, `timeout`) fails
228
228
  * the merge instead of silently disappearing. Within an array key the
229
229
  * template does emit on both sides (`preload`, `pathIgnorePatterns`,
230
230
  * `coveragePathIgnorePatterns`), entries the app appended on top of the
@@ -324,7 +324,7 @@ export function runScreenshots(scenarios: readonly Scenario[], opts: FlatOptions
324
324
  // Browser-context locale for JS-side Intl/navigator.language (e.g. money-input's
325
325
  // resolvedLocale) — pinEnglishLocale() only seeds the app's own kumiko:locale.
326
326
  // ponytail: native <input type="number"> still formats per the host OS region,
327
- // unreachable from Playwright (context.locale and --lang both no-op there). #1851
327
+ // unreachable from Playwright (context.locale and --lang both no-op there).
328
328
  if (opts.pinLocale) test.use({ locale: "en-US" });
329
329
  for (const s of scenarios) {
330
330
  test(
@@ -556,7 +556,7 @@ export function runMatrix<T extends string>(
556
556
  test.describe(locale, () => {
557
557
  // Browser-context locale for JS-side Intl/navigator.language — the
558
558
  // kumiko:locale seed below only drives the app's own i18n strings.
559
- // ponytail: see the runScreenshots() locale comment above / #1851
559
+ // ponytail: see the runScreenshots() locale comment above.
560
560
  const tag = resolveLocaleTag(locale, opts.localeTags);
561
561
  test.use({ locale: tag });
562
562
 
@@ -51,7 +51,7 @@ function parseJsonBody<S extends z.ZodType>(schema: S, raw: string): ParsedBody<
51
51
  }
52
52
 
53
53
  // Shared by every verify() below — a failed parse becomes a 400 the same way
54
- // the pre-#3050 handler-level parseJsonBody/parseWith checks did.
54
+ // the handler-level parseJsonBody/parseWith checks did.
55
55
  function parseOrReject<T>(value: ParsedBody<T>): T {
56
56
  if (value.success) return value.data;
57
57
  throw new ExtraRouteRejection(400, { error: value.error });
@@ -153,9 +153,9 @@ function toCapturedMail(message: InboxMessage): CapturedMail {
153
153
  // still throw in every environment) — the *mounting* decision is the
154
154
  // caller's: use isE2eSeedingEnabled() to keep prod from ever registering
155
155
  // these route objects at all, e.g. `...(isE2eSeedingEnabled() ?
156
- // createE2eSeedRoutes() : [])` in a server entry that also runs in prod
157
- // (kumiko-framework#3120). Each route's own assertGateOpen() 404s outside
158
- // the seed condition regardless — this is belt-and-suspenders, not the only gate.
156
+ // createE2eSeedRoutes() : [])` in a server entry that also runs in prod.
157
+ // Each route's own assertGateOpen() 404s outside the seed condition regardless
158
+ // — this is belt-and-suspenders, not the only gate.
159
159
  export function createE2eSeedRoutes(
160
160
  options: E2eSeedRoutesOptions,
161
161
  bundled: SeedRouteBundledApi,
@@ -68,7 +68,7 @@ function ensureEntityListRowNavigation(
68
68
  // No `params` here: this same-entity target always resolves to
69
69
  // UPDATE mode (the renderer auto-fills entityId from row["id"]),
70
70
  // and entityEdit-update never reads search-params as initial
71
- // values — the boot-validator now rejects that combination (#1680).
71
+ // values — the boot-validator now rejects that combination.
72
72
  {
73
73
  kind: "navigate",
74
74
  id: "edit",
@@ -309,7 +309,7 @@ function buildEditFillOps(
309
309
  ops.push({ kind: "fill", field, value: String(v) });
310
310
  break;
311
311
  // embedded/money/timestamp/locatedTimestamp/file/image/files/images:
312
- // no generic interaction. Since #369 timestamp renders two inputs
312
+ // no generic interaction. Since timestamp renders two inputs
313
313
  // (date + time) that a single .fill() cannot drive; the test author
314
314
  // supplies a hand override or skips it.
315
315
  default:
@@ -489,7 +489,7 @@ function fieldToFixture(name: string, field: FieldDefinition): unknown {
489
489
  case "images":
490
490
  // File-upload fixtures are not generic yet: Playwright would have to supply
491
491
  // file contents, and the write API already expects uploaded fileRef UUIDs.
492
- // Can be added once a sample settles the paths (M4).
492
+ // Can be added once a sample settles the paths.
493
493
  return undefined;
494
494
  default:
495
495
  return undefined;
@@ -4,9 +4,9 @@
4
4
 
5
5
  // The four cache/injection resets stay in their own modules (they close over
6
6
  // module-private state) and are only re-exported here — they are out of /crypto
7
- // and /db as of #1631. A production call to resetPiiSubjectKmsForTests() silently
8
- // switches the PII layer off, and subject-annotated fields are written in
9
- // plaintext from then on: no error, no log.
7
+ // and /db. A production call to resetPiiSubjectKmsForTests() silently switches
8
+ // the PII layer off, and subject-annotated fields are written in plaintext from
9
+ // then on: no error, no log.
10
10
  export {
11
11
  resetBlindIndexKeyForTests,
12
12
  resetEntityFieldEncryptionCacheForTests,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Run `fn` with `globalThis.Temporal` deleted, then restore.
3
- * Used by ambient-independence regression tests (kumiko-framework#1525/#1550).
3
+ * Used by ambient-independence regression tests.
4
4
  */
5
5
  export async function withoutAmbientTemporal<T>(fn: () => T | Promise<T>): Promise<T> {
6
6
  const savedGlobal: unknown = Reflect.get(globalThis, "Temporal");
package/src/seed-types.ts CHANGED
@@ -28,7 +28,7 @@ export type SeededUser = SeededCredentials & {
28
28
  export type SeedPart = (ctx: { readonly tenant: SeededTenant }) => Promise<void>;
29
29
 
30
30
  // email may contain the literal "{tenantId}" placeholder, substituted with the
31
- // seeded tenant's id — user:create's email uniqueness is global (fw#2134/#2593),
31
+ // seeded tenant's id — user:create's email uniqueness is global,
32
32
  // so a fixed literal email collides across per-scenario tenants.
33
33
  export type SeedAdminIdentity = {
34
34
  readonly displayName?: string;
@@ -7,9 +7,8 @@ export type TestRedis = {
7
7
  // The exact REDIS_URL used to build `redis` above — for a second, unrelated
8
8
  // connection (e.g. the test-stack's JobRunner) that needs its own client
9
9
  // rather than sharing this one's keyPrefix. Reconstructing a URL from
10
- // `redis.options` loses password/username/tls/path (pr-review
11
- // kumiko-framework #1036/2) — callers needing a fresh connection should use
12
- // this raw string, not rebuild one from parsed options.
10
+ // `redis.options` loses password/username/tls/path — callers needing a fresh
11
+ // connection should use this raw string, not rebuild one from parsed options.
13
12
  redisUrl: string;
14
13
  /** The per-test `keyPrefix` on `redis`, e.g. `kt:1a2b3c4d:`. */
15
14
  keyPrefix: string;
@@ -109,7 +109,7 @@ export type RequestHelper = {
109
109
  export type RequestHelperOptions = {
110
110
  // When sessionChecker is wired (sessions feature), JWTs without jti are
111
111
  // rejected as no_sid. Seed/test helpers that only jwt.sign(user) need a
112
- // live sid — create one via the same sessionCreator login uses (#1372).
112
+ // live sid — create one via the same sessionCreator login uses.
113
113
  readonly sessionCreator?: SessionCreator;
114
114
  };
115
115
 
@@ -90,7 +90,7 @@ export type TestStack = {
90
90
  // The AppContext buildServer handed the request path, incl. the fields it
91
91
  // wires itself (_fileProviderResolver). A dev-server that starts its own
92
92
  // lane job-runners beside this stack must hand them THIS, not a
93
- // `{ db, registry }` literal — that's the #1232 drift, and it makes an
93
+ // `{ db, registry }` literal — that's the drift, and it makes an
94
94
  // event-triggered job reaching for ctx.files die where the request path works.
95
95
  context: AppContext;
96
96
  // Present whenever a system consumer (SSE, Search) or
@@ -253,11 +253,11 @@ export type TestStackOptions = {
253
253
  /** Override the event dispatcher's polling-timer interval. Default 50ms.
254
254
  * Tests that assert LISTEN/NOTIFY wake-up latency need this pushed far
255
255
  * out (e.g. 60_000) so the polling timer can't land inside the
256
- * assertion window and mask a dead subscription — see E.4 (#2042). */
256
+ * assertion window and mask a dead subscription. */
257
257
  eventDispatcherPollIntervalMs?: number;
258
258
  /** Opt out of auto-created r.entity() tables for callers that create/migrate
259
259
  * them themselves. Default true — false pushes only projection/MSP/
260
- * storeTable sources, same as before fw#3102. */
260
+ * storeTable sources, same as before. */
261
261
  entityTables?: boolean;
262
262
  /** Time source of the stack's rate-limit resolver, so tests can freeze the
263
263
  * clock instead of racing the window. Default: system time. */
@@ -312,7 +312,7 @@ function bindMfaTokenSecrets(features: readonly FeatureDefinition[], jwtSecret:
312
312
  }
313
313
 
314
314
  // Same table list as `kumiko schema generate` (collectTableMetas) — divergence
315
- // was the #255 prod-crash and the #3102 missing r.entity() tables.
315
+ // caused a production crash and left r.entity() tables missing.
316
316
  async function collectStackTableMetas(
317
317
  options: TestStackOptions,
318
318
  ): Promise<readonly EntityTableMeta[]> {
@@ -401,9 +401,9 @@ export async function setupTestStack(options: TestStackOptions): Promise<TestSta
401
401
  const { ensureTemporalPolyfill } = await import("@cosmicdrift/kumiko-framework/time");
402
402
  await ensureTemporalPolyfill();
403
403
 
404
- // Ownership boot-guards (fw#2639 unqualified where-fragments, fw#2626
405
- // where-rules on the write path) otherwise run only in the prod boot via
406
- // validateBoot, leaving every test stack blind to a broken access map.
404
+ // Ownership boot-guards (unqualified where-fragments, where-rules on the
405
+ // write path) otherwise run only in the prod boot via validateBoot, leaving
406
+ // every test stack blind to a broken access map.
407
407
  // Runs after the polyfill (buildEntityTable needs it to derive the probe
408
408
  // columns) and before the ephemeral DB/Redis exist, so a throw can't leak
409
409
  // a database that nothing will clean up.
@@ -504,16 +504,16 @@ export async function setupTestStack(options: TestStackOptions): Promise<TestSta
504
504
 
505
505
  // Same AppContext buildServer() gets below (db/redis/searchAdapter/
506
506
  // entityCache/masterKeyProvider/fileProviderResolver/extraContext) —
507
- // shared so the job context can't drift from the request-path context
508
- // (kumiko-framework#1232: a reduced `{ db, registry }` literal let jobs
509
- // pass in tests while reaching for fields only prod's context has).
507
+ // shared so the job context can't drift from the request-path context:
508
+ // a reduced `{ db, registry }` literal let jobs pass in tests while
509
+ // reaching for fields only prod's context has.
510
510
  //
511
511
  // effectiveFeatures deliberately stays OUT of appContext — prod never puts
512
512
  // it there either (only dispatcherOptions.effectiveFeatures, consumed by
513
513
  // the command-dispatcher — see buildJobRunnerWithHook in entrypoint/
514
514
  // index.ts). Putting it here would reintroduce the exact test-vs-prod
515
- // drift #1232 fixed: a job/handler reading `ctx.effectiveFeatures` would
516
- // pass in tests and break in prod (kumiko-framework#1255).
515
+ // drift fixed: a job/handler reading `ctx.effectiveFeatures` would pass in
516
+ // tests and break in prod.
517
517
  const appContext = {
518
518
  db: testDb.db,
519
519
  redis: testRedis.redis,
@@ -547,8 +547,8 @@ export async function setupTestStack(options: TestStackOptions): Promise<TestSta
547
547
  jobRunner = createJobRunner({
548
548
  registry,
549
549
  context: { ...appContext, tracer: observability.tracer, meter: observability.meter },
550
- // The real REDIS_URL, not one rebuilt from `.options` — that lost
551
- // password/username/tls/path (pr-review kumiko-framework #1036/2).
550
+ // The real REDIS_URL, not one rebuilt from `.options` — rebuilding it lost
551
+ // password/username/tls/path.
552
552
  redisUrl: testRedis.redisUrl,
553
553
  ...(options.jobs.consumerLane !== undefined && { consumerLane: options.jobs.consumerLane }),
554
554
  queueNamePrefix:
@@ -582,7 +582,7 @@ export async function setupTestStack(options: TestStackOptions): Promise<TestSta
582
582
  // above (createJobRunner() itself opens live BullMQ Queue/lock Redis
583
583
  // connections, .start() adds a live worker) — otherwise a failing
584
584
  // buildServer()/search-config/etc. leaks that connection and the test
585
- // process hangs on exit (pr-review kumiko-framework #1036/1).
585
+ // process hangs on exit.
586
586
  try {
587
587
  if (jobRunner) await jobRunner.start();
588
588