create-flowdular 0.6.0 → 0.6.2

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 (64) hide show
  1. package/agent-template/.agents/skills/module-new/SKILL.md +1 -1
  2. package/agent-template/.agents/skills/module-update/SKILL.md +1 -1
  3. package/agent-template/.agents/skills/perf-audit/SKILL.md +1 -1
  4. package/agent-template/.agents/skills/spec-approval/SKILL.md +6 -2
  5. package/agent-template/.agents/skills/spec-interview/SKILL.md +2 -2
  6. package/agent-template/.ai/agents/README.md +1 -1
  7. package/agent-template/.ai/agents/sandbox/agentic-engineer.md +1 -1
  8. package/agent-template/.ai/agents/sandbox/backend-engineer.md +1 -1
  9. package/agent-template/.ai/agents/sandbox/business-manager.md +2 -4
  10. package/agent-template/.ai/agents/sandbox/frontend-engineer.md +1 -1
  11. package/agent-template/.ai/agents/sandbox/ux-designer.md +1 -1
  12. package/agent-template/.ai/platform-capabilities.md +4 -4
  13. package/agent-template/.ai/policies/model-routing.yaml +2 -1
  14. package/agent-template/.ai/policies/task-budgets.yaml +1 -1
  15. package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.up.sql +2 -2
  16. package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.up.sql +2 -2
  17. package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql +2 -2
  18. package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql +2 -2
  19. package/agent-template/.ai/references/catalog/module.json +3 -3
  20. package/agent-template/.ai/references/catalog/package.json +2 -2
  21. package/agent-template/.ai/references/catalog/spec/module.yaml +3 -3
  22. package/agent-template/.ai/references/catalog/src/client/CatalogItemForm.tsrx +2 -2
  23. package/agent-template/.ai/references/catalog/src/services/migration.ts +8 -8
  24. package/agent-template/.ai/references/catalog/tests/migrations.test.ts +1 -1
  25. package/agent-template/.ai/skills/module-new/SKILL.md +1 -1
  26. package/agent-template/.ai/skills/module-update/SKILL.md +1 -1
  27. package/agent-template/.ai/skills/perf-audit/SKILL.md +1 -1
  28. package/agent-template/.ai/skills/spec-approval/SKILL.md +6 -2
  29. package/agent-template/.ai/skills/spec-interview/SKILL.md +2 -2
  30. package/agent-template/.claude/skills/module-new/SKILL.md +1 -1
  31. package/agent-template/.claude/skills/module-update/SKILL.md +1 -1
  32. package/agent-template/.claude/skills/perf-audit/SKILL.md +1 -1
  33. package/agent-template/.claude/skills/spec-approval/SKILL.md +6 -2
  34. package/agent-template/.claude/skills/spec-interview/SKILL.md +2 -2
  35. package/agent-template/docs/adr/0003-module-settings.md +2 -0
  36. package/agent-template/docs/agent-contract.md +1 -1
  37. package/agent-template/docs/cli-extensions.md +1 -0
  38. package/agent-template/docs/cli.md +16 -0
  39. package/agent-template/docs/configuration.md +32 -4
  40. package/agent-template/docs/database-adapters.md +10 -2
  41. package/agent-template/docs/design-system.md +6 -2
  42. package/agent-template/docs/getting-started.md +5 -1
  43. package/agent-template/docs/module-distribution.md +1 -2
  44. package/agent-template/docs/modules.md +5 -3
  45. package/agent-template/docs/sandbox.md +64 -7
  46. package/package.json +1 -1
  47. package/template/default/.env.example +5 -0
  48. package/template/default/infra/docker/.env.example +5 -0
  49. package/template/default/infra/docker/Dockerfile +5 -1
  50. package/template/default/infra/docker/compose.yaml +4 -0
  51. package/template/default/infra/kubernetes/deployment.yaml +5 -0
  52. package/template/default/infra/sdk-module-manifests.mjs +118 -0
  53. package/template/default/infra/vercel/build.mjs +9 -0
  54. package/template/default/modules/example/package.json +1 -1
  55. package/template/default/package.json +2 -3
  56. package/template/default/platform/octane.config.ts +53 -15
  57. package/template/default/platform/package.json +1 -1
  58. package/template/default/platform/scripts/dev.mjs +66 -21
  59. package/template/default/platform/src/server/lifecycle.ts +325 -0
  60. package/template/default/platform/src/server/setup/modules.ts +28 -32
  61. package/template/default/platform/src/server/setup/page.ts +54 -3
  62. package/template/default/platform/src/server/setup/routes.ts +1 -0
  63. package/template/default/platform/src/server/setup/seed.ts +51 -4
  64. package/agent-template/.ai/references/catalog.provenance.json +0 -65
@@ -304,6 +304,42 @@ ${steps(view.step, view.databasePreconfigured)}${alerts(view)}
304
304
  const WORKSPACE_SLUG_INPUT_PATTERN =
305
305
  '(?!.*--)[a-z0-9][a-z0-9\\-]{1,46}[a-z0-9]';
306
306
 
307
+ /* What the address field keeps of typed or pasted text. Accented letters fold
308
+ to their base letter: NFD splits the accent off and the drop below removes
309
+ it, and the map covers letters that do not decompose. A short value and a
310
+ trailing hyphen pass, because typing goes through both; the pattern and the
311
+ server refuse them on submit. Every step reads left to right, one character
312
+ at a time, so filtering the text up to the end of an edit tells what that
313
+ edit may insert. The page ships this source and tests evaluate it. */
314
+ export const WORKSPACE_SLUG_TYPING_FILTER = String.raw`(function(){var fold={'ł':'l','Ł':'l','ø':'o','Ø':'o','đ':'d','Đ':'d','ð':'d','Ð':'d','þ':'th','Þ':'th','æ':'ae','Æ':'ae','œ':'oe','Œ':'oe','ß':'ss','ẞ':'ss','ı':'i'};
315
+ return function(value){return value.normalize('NFD').replace(/[^\x00-\x7f]/g,function(c){return fold[c]||c;}).toLowerCase().replace(/\s/g,'-').replace(/[^a-z0-9-]/g,'').replace(/-{2,}/g,'-').replace(/^-/,'').slice(0,48);};})()`;
316
+
317
+ /* An insertion at the selection that the page may cancel is filtered before
318
+ the browser applies it and replayed as an editing command, so undo, redo,
319
+ the caret and maxlength only ever see filtered text; assigning the value
320
+ instead corrupts Chrome's undo history. A failed replay lets the raw edit
321
+ through for the pattern to refuse. Deletions pass untouched: they add no
322
+ character, and rewriting them would erase separators mid-edit. Composed
323
+ text is filtered once committed, in every engine. */
324
+ const WORKSPACE_SLUG_TYPING = `
325
+ (function(filter){var input=document.getElementById('setup-workspaceSlug');if(!input)return;
326
+ function kept(start,end,text){var value=input.value,head=value.slice(0,start);
327
+ var next=filter(head+text).slice(filter(head).length);
328
+ return next.slice(-1)==='-'&&value.charAt(end)==='-'?next.slice(0,-1):next;}
329
+ function insert(text){return document.execCommand(text?'insertText':'delete',false,text);}
330
+ input.addEventListener('beforeinput',function(event){
331
+ if(!event.cancelable||event.isComposing||!/^insert(Text|FromPaste|FromDrop)$/.test(event.inputType))return;
332
+ var text=event.data!=null?event.data:event.dataTransfer?event.dataTransfer.getData('text/plain'):'';
333
+ var next=kept(input.selectionStart,input.selectionEnd,text);
334
+ if(next!==text&&(!next||insert(next)))event.preventDefault();});
335
+ input.addEventListener('compositionend',function(event){
336
+ var text=event.data||'',end=input.selectionStart,start=end-text.length;
337
+ if(!text||start<0||input.value.slice(start,end)!==text)return;
338
+ var next=kept(start,end,text);
339
+ if(next!==text){input.setSelectionRange(start,end);insert(next);}});
340
+ })(${WORKSPACE_SLUG_TYPING_FILTER});
341
+ `;
342
+
307
343
  function workspaceField(
308
344
  view: SetupPageView,
309
345
  name: string,
@@ -394,7 +430,7 @@ ${
394
430
  </ul></div>
395
431
  <div><p class="setup-label setup-sublabel">Enabled modules that own tables</p><ul class="setup-list">${modules || '<li><span class="setup-help">No enabled module owns database tables.</span></li>'}</ul>${
396
432
  view.modulesApproximated
397
- ? '<p class="setup-note setup-note--gap">This build ships without the module manifests, so every enabled module is checked against the strictest requirements any of them can ask for.</p>'
433
+ ? '<p class="setup-note setup-note--gap">This build ships without some module manifests, so each enabled module without one is checked against the strictest requirements any module can ask for.</p>'
398
434
  : ''
399
435
  }</div>
400
436
  <form class="setup-form" method="post" action="/setup">${csrf(view)}
@@ -430,6 +466,17 @@ function environmentSection(result: EnvironmentWriteResult): string {
430
466
  }.</p>`;
431
467
  }
432
468
 
469
+ function ungrantedNotice(modules: readonly string[]): string {
470
+ if (modules.length === 0) return '';
471
+ const commands = modules
472
+ .map(
473
+ (id) =>
474
+ `<br><code>pnpm flowdular auth sync-scopes --module ${escapeHtml(id)} --apply</code>`,
475
+ )
476
+ .join('');
477
+ return `<p class="setup-alert setup-alert--warning" role="alert">The owner was not granted the permissions of ${escapeHtml(modules.join(', '))}. Run ${modules.length === 1 ? 'this command' : 'these commands'} with this deployment's database settings (stop the app first if it uses the embedded database), then sign in:${commands}</p>`;
478
+ }
479
+
433
480
  function doneStep(view: SetupPageView): string {
434
481
  const seed = view.seed;
435
482
  const owner = seed?.accounts[0];
@@ -445,7 +492,7 @@ function doneStep(view: SetupPageView): string {
445
492
  : 'Restart this deployment to leave setup and open the sign-in screen.';
446
493
  return `<header><span class="setup-kicker">Sign in</span><h2>Flowdular is ready</h2>
447
494
  <p class="setup-card__sub">The workspace ${escapeHtml(seed?.workspace.name ?? '')} is ready. ${nextStep}</p></header>
448
- ${steps(view.step, view.databasePreconfigured)}${alerts(view)}
495
+ ${steps(view.step, view.databasePreconfigured)}${alerts(view)}${ungrantedNotice(seed?.ungrantedModules ?? [])}
449
496
  <div><p class="setup-label setup-sublabel">Sign in as the workspace owner</p><div class="setup-credentials"><div><b>Owner account</b><code>${escapeHtml(owner?.email ?? view.values.ownerEmail ?? '')}</code></div></div>
450
497
  <p class="setup-note setup-note--gap">After signing in, you can connect an AI model in Providers. This is optional and can be done later.</p></div>
451
498
  ${view.environment ? environmentSection(view.environment) : ''}
@@ -459,6 +506,10 @@ export function renderSetupPage(view: SetupPageView, nonce: string): string {
459
506
  view.step === 'Sign in' && view.autoRestart && view.csrfToken
460
507
  ? `<script nonce="${nonce}">fetch('/setup',{method:'POST',credentials:'same-origin',headers:{'content-type':'application/x-www-form-urlencoded'},body:new URLSearchParams({step:'restart',setupCsrf:'${view.csrfToken}'}),keepalive:true}).catch(()=>{});</script>`
461
508
  : '';
509
+ const slugScript =
510
+ view.step === 'Workspace'
511
+ ? `<script nonce="${nonce}">${WORKSPACE_SLUG_TYPING}</script>`
512
+ : '';
462
513
  const body =
463
514
  view.step === 'Unlock'
464
515
  ? unlockStep(view)
@@ -492,6 +543,6 @@ function sync(){for(var i=0;i<f.length;i++){var s=document.querySelector('fields
492
543
  if(s)s.hidden=!f[i].checked;}}
493
544
  for(var i=0;i<f.length;i++)f[i].addEventListener('change',sync);sync();})();
494
545
  </script>
495
- ${restartScript}
546
+ ${slugScript}${restartScript}
496
547
  </body></html>`;
497
548
  }
@@ -191,6 +191,7 @@ function page(
191
191
  `style-src 'nonce-${nonce}'`,
192
192
  `script-src 'nonce-${nonce}'`,
193
193
  "img-src 'self' data:",
194
+ "connect-src 'self'",
194
195
  "form-action 'self'",
195
196
  "base-uri 'none'",
196
197
  "frame-ancestors 'none'",
@@ -3,6 +3,7 @@ import {
3
3
  authRuntimeOptionsFromEnvironment,
4
4
  createAuthRuntime,
5
5
  } from '@flowdular/sdk/modules/auth/server';
6
+ import { readModuleCatalog } from '@flowdular/sdk/modules/system/server';
6
7
  /* First-run provisioning uses the same audited auth service as the operator
7
8
  CLI. The operator chooses the first owner; no demo credentials are shipped. */
8
9
 
@@ -26,6 +27,8 @@ export interface FirstRunOwner {
26
27
  export interface FirstRunSeed {
27
28
  readonly workspace: { readonly name: string; readonly slug: string };
28
29
  readonly accounts: readonly SeededAccount[];
30
+ /** Enabled modules whose permissions setup could not grant to the owner. */
31
+ readonly ungrantedModules: readonly string[];
29
32
  }
30
33
 
31
34
  export class SetupSeedError extends Error {
@@ -38,10 +41,19 @@ export class SetupSeedError extends Error {
38
41
  }
39
42
  }
40
43
 
44
+ /* A driver message can carry a host or a connection string, so only a code
45
+ from a fixed alphabet is logged, such as a SQLSTATE or an errno name. */
46
+ function stableCode(error: unknown): string {
47
+ const code = (error as { code?: unknown } | null)?.code;
48
+ if (typeof code === 'string' && /^[A-Z0-9_]{1,64}$/.test(code)) return code;
49
+ return error instanceof Error ? error.name : 'unknown';
50
+ }
51
+
41
52
  /**
42
- * Migrates auth.core, then creates the chosen workspace and its owner. The
43
- * database must still have no workspace, so a stale session cannot re-provision
44
- * an existing installation.
53
+ * Migrates auth.core, then creates the chosen workspace and its owner, and
54
+ * grants that owner the permissions the enabled modules declare. The database
55
+ * must still have no workspace, so a stale session cannot re-provision an
56
+ * existing installation.
45
57
  */
46
58
  export async function seedFirstRun(
47
59
  databases: DatabaseProvider,
@@ -49,6 +61,9 @@ export async function seedFirstRun(
49
61
  workspaceRoot: string,
50
62
  owner: FirstRunOwner,
51
63
  ): Promise<FirstRunSeed> {
64
+ const enabled = readModuleCatalog(workspaceRoot).filter(
65
+ (entry) => entry.enabled,
66
+ );
52
67
  const runtime = createAuthRuntime({
53
68
  ...authRuntimeOptionsFromEnvironment(environment, workspaceRoot),
54
69
  databases,
@@ -72,6 +87,37 @@ export async function seedFirstRun(
72
87
  password: owner.ownerPassword,
73
88
  operator: FIRST_RUN_OPERATOR,
74
89
  });
90
+ /* An application's own modules declare permissions the owner defaults
91
+ cannot carry, and the grant module enable runs found no workspace
92
+ before this one. The workspace is committed and first run is over, so
93
+ a failed grant is reported with its repair command rather than failing
94
+ a setup that cannot run again. */
95
+ const held = new Set(provisioned.owner.scopes);
96
+ const pending = enabled.filter((entry) =>
97
+ entry.permissions.some((permission) => !held.has(permission.id)),
98
+ );
99
+ let scopes = provisioned.owner.scopes;
100
+ let ungrantedModules: readonly string[] = [];
101
+ if (pending.length > 0) {
102
+ try {
103
+ const grants = await service.grantModuleScopes(
104
+ pending.flatMap((entry) =>
105
+ entry.permissions.map((permission) => permission.id),
106
+ ),
107
+ );
108
+ scopes = [
109
+ ...scopes,
110
+ ...(grants.find(
111
+ (grant) => grant.accountId === provisioned.owner.accountId,
112
+ )?.granted ?? []),
113
+ ];
114
+ } catch (error) {
115
+ ungrantedModules = pending.map((entry) => entry.id);
116
+ console.warn(
117
+ `First-run setup could not grant the owner the permissions of ${ungrantedModules.join(', ')} (${stableCode(error)}).`,
118
+ );
119
+ }
120
+ }
75
121
  return {
76
122
  workspace: {
77
123
  name: provisioned.workspace.name,
@@ -82,9 +128,10 @@ export async function seedFirstRun(
82
128
  email: provisioned.owner.email,
83
129
  displayName: provisioned.owner.displayName,
84
130
  role: provisioned.owner.role,
85
- scopes: provisioned.owner.scopes,
131
+ scopes,
86
132
  },
87
133
  ],
134
+ ungrantedModules,
88
135
  };
89
136
  } finally {
90
137
  await runtime.dispose();
@@ -1,65 +0,0 @@
1
- {
2
- "id": "catalog.core",
3
- "version": "0.8.2",
4
- "repository": "Flowdular/official-modules",
5
- "sourceCommit": "f38a67718c5a29aba5b5d37c0504430a3c7f565b",
6
- "artifactSha256": "149808831d620ac0ebc50abb6b0fb2caef6bec66b5d7821c752ec811e5d9219f",
7
- "files": {
8
- "LICENSE": "155d722071bad9d0d832482e06fd5a47f7034389cb63aabcb39f4282aa3499fc",
9
- "migrations/0001_catalog_core.down.sql": "0962a1edf0bde959cd4facccf77bd5b634d6cc25f125a0c79a61770c8871093f",
10
- "migrations/0001_catalog_core.up.sql": "602ed9c1852b729cf278cf8536f79e3f7432f23a5a60c50d8826f5c1b9442d18",
11
- "migrations/0002_catalog_history.down.sql": "7f163e11ca9033101e3bb1de61481b1a8043c204e65aa2bb508a13b065e98c78",
12
- "migrations/0002_catalog_history.up.sql": "3aa30993b1676cf357c2ef87f19a7d4b64b77041c0e4bc743fced04521471c28",
13
- "migrations/0003_catalog_history_service_actors.down.sql": "f20ecc8d7d753af3d2b6fdbff9d637fd938884cfbd88b08a30958e6aa000132b",
14
- "migrations/0003_catalog_history_service_actors.up.sql": "7caae787ca2fc1e331ccbfda4df5982beec76136e8dc486aab5532ccd338a722",
15
- "migrations/0004_catalog_idempotency_ledger.down.sql": "8ba72d8edc4d25ecf6d041888cf321690c25afdaf3723812ddd7d391d75370aa",
16
- "migrations/0004_catalog_idempotency_ledger.up.sql": "41e86ba2051159c6cc9672bfae17c1d02051da975f1c43c566a2b66592673cb0",
17
- "migrations/0005_catalog_list_indexes.down.sql": "3dd547d738e75513abef502afc4bf9b51851ec9405b6b719c6134b897c5b1776",
18
- "migrations/0005_catalog_list_indexes.up.sql": "dc3ece30b93fba0c91be58f772d1ae421cfbba49439e8c72a06aead6720f5db5",
19
- "migrations/README.md": "2a15fd001713c2552a3c82b186246aa5fec136f43143cc2d9aa15bd491a09d41",
20
- "module.json": "d2a98b70d60a433e1b3b6547352781048d562b996e3ee961f519d61ee1b623b9",
21
- "package.json": "c23a99016f974d183189a05e4cfc4929788a46ae1ad65c623d66513e0880cdbd",
22
- "spec/module.yaml": "992953d002574e83374c21e1ee7bef1d451c04b0180892856838d7c67404ce66",
23
- "src/acl/permissions.ts": "3375521a5a229736ffac5a948140ec347dc7a7e4fba80e778c0baaf9e0622590",
24
- "src/agent/tools.ts": "3403db7954906dc2c79227ba0420b5cb4bfb57063b7cfc285e6e556f16be9266",
25
- "src/api/endpoints.ts": "205ef36d058f246f99b77336e7246a23aaca611c696a1f6f09758f66e8a93a29",
26
- "src/api/list-cursor.ts": "dcb763edc0128a3aac95e9ca3c5158611a7f2c6a4c71484438c89b7f4d79bb0d",
27
- "src/client/CatalogHistoryDrawer.tsrx": "6cdba5249be81e70da703cb34c1a2210943ce5e5fb596ee77cf7952e2acf3ee3",
28
- "src/client/CatalogItemForm.tsrx": "d621ac2a513635a5e38ee44726c07926bf035ec5e0dddca487c462cc7913d040",
29
- "src/client/CatalogView.tsrx": "2c3e49bb1e54b58d636de0ddbb6ece429acf6aeadb6a0515ab52fca3baabec21",
30
- "src/client/api.ts": "eaa55af81d26aa0190d19b3102c363c1ee25b2bdc05436446ac95dcde62aea75",
31
- "src/client/contribution.tsrx": "6cbf79e6188bdf24b9cec4a06ae621e03efd5d0c76ad72b28828eee9155ab893",
32
- "src/client/index.ts": "03eb0664cdafccb66cb25f2e1b07e6959c2dfa9bdbfffc3e7edf9b535ba4949a",
33
- "src/client/navigation-copy.ts": "9a8757e64f4001a93e2bc2861c686a19f791f9d67a396d9e658023b1ec4cea8f",
34
- "src/client/state.ts": "61601f6037c4bb8a709b69b10c1a37e59b45b0c941240c436f7861c2b034dcc1",
35
- "src/domain/lists.ts": "83749967f99fa0c4f44abc0c614108b844321e50ce6408553215e6233ad6e350",
36
- "src/domain/types.ts": "374efeb24c4f7d41e3c660336e721fa362418579837d44a46724076d03287a0b",
37
- "src/domain/variables.ts": "131130e57838235b1f3fcb799da44baeae16522bb346d522827e022305c110b5",
38
- "src/index.ts": "5b27943018db9a18651d62add7d6f8397d7c492a204381fae74547b99b91990d",
39
- "src/platform.ts": "f048082a33c1c688e4952750c762c8b65a4626ff52cc9c4eaca2156014bac631",
40
- "src/server/index.ts": "90eae107d863418124e5d10c4d1fe8a119bd14da605b36de708c18d8500c4b5e",
41
- "src/server/runtime.ts": "5f4389a6adf8265f6737c489baf686f63cc3550662103d28b2da9800dd9f5b63",
42
- "src/services/catalog-service.ts": "66e61dfbd9797d31e6814c18efcd21cfcb7b220f7df22677868f486f3fa0e9d1",
43
- "src/services/data-classes.ts": "ea09b1a7def59fee43d57ca7dab6fdb4d646b51df2cacb60af96676c43602b33",
44
- "src/services/database-repository.ts": "1b72ce91a2f85f6572825766781a806d94fe0d2abb91872ee9acae3b1e70db2e",
45
- "src/services/index.ts": "a08aefe5101814538666f861536287fc382e6c655d62ba9b9ef4bbfbc6ede4af",
46
- "src/services/item-export.ts": "b2a4613b43a98d0d41699481bb5e85a770f9a60cb2241579b065effb6936c80b",
47
- "src/services/migration.ts": "57c9a857d4074973e14b5e3a1c4548a92ad0faca371419e7daf2334f3ef701ab",
48
- "src/services/repository.ts": "9f560033875d05654148b4a11897465ee4eefa0d7fa701439e8f562da9fba1db",
49
- "src/services/target-idempotency.ts": "7111b56a30b691eaaaa64f5691895ac94b6e0735b0079794835bbbeba5102cb0",
50
- "tests/agent-tools.test.ts": "7762c14bc353ee3085df46a91cf370eb5c25b2edb7096f0a4b0e033f220ea726",
51
- "tests/client-state.test.ts": "ea146c793b14d0f9bc5e36d92e92894ced6531b8fcbd11c8be1486b62313b8c3",
52
- "tests/data-classes.test.ts": "bea08e4d1d7380ccdebc211374b74a6034714b192fd98bfb90a2218067b35658",
53
- "tests/endpoints.test.ts": "a2d700f4c3eb6fbbef5c57ed5591017a27c98e17fe84fba8426fcd3a2820b210",
54
- "tests/export.test.ts": "de83066272cee5f7f5736d636d7b9b97dab09778ba661816e401bf926b826402",
55
- "tests/idempotency.test.ts": "faea4a2cfa04e81b7155399cba807af4c1ba4448cdfeab733d1afe801d27734f",
56
- "tests/list.test.ts": "97605b50020841cbdac62f9d44b65f0f7dce9c4c4972af6409afeb6b9b66e59a",
57
- "tests/migrations.test.ts": "fb796aecedb997f6395c2c15e45bf4abfae4677953fa8cb420c94e9cfba8222f",
58
- "tests/module.test.ts": "af961a5bcddc41d304d14841f8810976f43f46b46ab7814142fdb921a773e92a",
59
- "tests/support/database.ts": "4ff6d093ca2e80baab3dea476018661473d6474db63d67655f1edc667b8472ac",
60
- "translations/en.json": "a86d70e02ccf46a2a132d5bee0de7c528c0eb56a85c269a78e0c2e7e0de24e37",
61
- "translations/pl.json": "8157d83467e9dd8d9700e2fb188f1a730073f805d2a8b3f0ba98f02f2ca9a264",
62
- "tsconfig.json": "140bb4775df421146563d13d2f78ff74cb3c2decab6737db32938339248a92ba",
63
- "vitest.config.ts": "d13725b13c3712ec91c1646e9226fb172eec2599f72f4e6608bece9912e2bd81"
64
- }
65
- }