create-kumiko-app 0.4.150 → 0.4.151

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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "source": "samples/apps/use-all-bundled APP_FEATURES (composeFeatures includeBundled)",
3
- "featureCount": 57,
2
+ "source": "samples/apps/use-all-bundled APP_FEATURES (composeFeatures includeBundled + signup)",
3
+ "featureCount": 59,
4
4
  "features": [
5
5
  {
6
6
  "name": "admin-shell",
@@ -52,7 +52,8 @@
52
52
  "toggleableDefault": null,
53
53
  "requires": [
54
54
  "user",
55
- "tenant"
55
+ "tenant",
56
+ "delivery"
56
57
  ],
57
58
  "optionalRequires": [],
58
59
  "configReads": [],
@@ -64,7 +65,9 @@
64
65
  "writeHandlers": [
65
66
  "auth-email-password:write:change-password",
66
67
  "auth-email-password:write:login",
67
- "auth-email-password:write:logout"
68
+ "auth-email-password:write:logout",
69
+ "auth-email-password:write:signup-confirm",
70
+ "auth-email-password:write:signup-request"
68
71
  ],
69
72
  "uiHints": {
70
73
  "displayLabel": "Auth · Email + Password",
@@ -202,6 +205,20 @@
202
205
  "secrets": [],
203
206
  "writeHandlers": []
204
207
  },
208
+ {
209
+ "name": "auth-self-registration",
210
+ "description": "Runtime on/off switch for the auth-email-password self-signup flow. Handler-less: composing it registers \"auth-self-registration\" as a toggleable feature (default ON). auth-email-password's signup-request handler and its `signupRegistrationStatus` query both read `ctx.hasFeature(\"auth-self-registration\")` — the query stays reachable when the toggle is off (deliberately not gated itself) so the public signup page can hide its own link/form. Only meaningful when `signup` is configured on `createAuthEmailPasswordFeature` — compose alongside it, then flip via the feature-toggles admin screen.",
211
+ "toggleableDefault": true,
212
+ "requires": [],
213
+ "optionalRequires": [],
214
+ "configReads": [],
215
+ "exposesApis": [],
216
+ "usesApis": [],
217
+ "extensionsUsed": [],
218
+ "configKeys": [],
219
+ "secrets": [],
220
+ "writeHandlers": []
221
+ },
205
222
  {
206
223
  "name": "billing-foundation",
207
224
  "description": "Plugin host for subscription billing — manages the `read_subscriptions` projection table and exposes 5 domain events (subscription created/updated/canceled, invoice paid/failed) appended by the foundation's own `billing-foundation:write:process-event` write-handler after provider plugins verify and normalize each webhook. Also ships `billing-foundation:write:create-checkout-session` and `billing-foundation:write:create-portal-session` write-handlers, a `billing-foundation:query:subscription:list` query handler, and a `createSubscriptionWebhookHandler` factory for the `/api/subscription/webhook/:providerName` route. Low-level building block — use `subscription-stripe` or `subscription-mollie` unless you are writing a new payment provider.",
@@ -1442,7 +1459,7 @@
1442
1459
  "uiHints": {
1443
1460
  "displayLabel": "Personal Access Tokens",
1444
1461
  "category": "identity",
1445
- "recommended": true
1462
+ "recommended": false
1446
1463
  }
1447
1464
  },
1448
1465
  {
@@ -2141,6 +2158,81 @@
2141
2158
  "recommended": false
2142
2159
  }
2143
2160
  },
2161
+ {
2162
+ "name": "tenant-settings",
2163
+ "description": "Per-tenant Currency + Locale defaults, exposed as two config keys (tenant-settings:config:currency, tenant-settings:config:locale) that surface in the self-populating Settings-Hub via `mask`. Pair with defineCreateWithTenantDefaults to auto-fill a money field's currency or a locale field on create instead of hard-coding a literal per entity.",
2164
+ "toggleableDefault": null,
2165
+ "requires": [
2166
+ "config"
2167
+ ],
2168
+ "optionalRequires": [],
2169
+ "configReads": [],
2170
+ "exposesApis": [],
2171
+ "usesApis": [],
2172
+ "extensionsUsed": [],
2173
+ "configKeys": [
2174
+ {
2175
+ "key": "currency",
2176
+ "qualifiedName": "tenant-settings:config:currency",
2177
+ "type": "select",
2178
+ "scope": "tenant",
2179
+ "default": "EUR",
2180
+ "encrypted": false,
2181
+ "computed": false,
2182
+ "options": [
2183
+ "EUR",
2184
+ "USD",
2185
+ "GBP",
2186
+ "CHF",
2187
+ "JPY",
2188
+ "SEK",
2189
+ "NOK",
2190
+ "DKK",
2191
+ "PLN",
2192
+ "CZK",
2193
+ "CAD",
2194
+ "AUD",
2195
+ "NZD",
2196
+ "CNY",
2197
+ "INR"
2198
+ ],
2199
+ "bounds": null,
2200
+ "pattern": null,
2201
+ "writeRoles": [
2202
+ "TenantAdmin",
2203
+ "Admin",
2204
+ "SystemAdmin"
2205
+ ],
2206
+ "readRoles": [
2207
+ "all"
2208
+ ]
2209
+ },
2210
+ {
2211
+ "key": "locale",
2212
+ "qualifiedName": "tenant-settings:config:locale",
2213
+ "type": "text",
2214
+ "scope": "tenant",
2215
+ "default": "en",
2216
+ "encrypted": false,
2217
+ "computed": false,
2218
+ "options": null,
2219
+ "bounds": null,
2220
+ "pattern": {
2221
+ "regex": "^[a-z]{2}(-[A-Z]{2})?$"
2222
+ },
2223
+ "writeRoles": [
2224
+ "TenantAdmin",
2225
+ "Admin",
2226
+ "SystemAdmin"
2227
+ ],
2228
+ "readRoles": [
2229
+ "all"
2230
+ ]
2231
+ }
2232
+ ],
2233
+ "secrets": [],
2234
+ "writeHandlers": []
2235
+ },
2144
2236
  {
2145
2237
  "name": "text-content",
2146
2238
  "description": "Generic Markdown text store keyed by `(tenantId, slug, lang)` — one row per combination in the `read_text_blocks` entity table. Provides `text-content:write:set` (TenantAdmin upsert) and `text-content:query:by-slug` (anonymous-capable read); use `SYSTEM_TENANT_ID` as the tenant for app-wide texts such as imprint, privacy policy, or FAQ. Other features (e.g. `legal-pages`) read blocks without a direct code import via the `createTextContentApi` / `requireTextContent` extraContext pattern.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kumiko-app",
3
- "version": "0.4.150",
3
+ "version": "0.4.151",
4
4
  "description": "`bun create kumiko-app <name>` — scaffold a new Kumiko app with an interactive feature picker.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -30,9 +30,9 @@
30
30
  "vendor:manifest": "bun run scripts/vendor-manifest.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@cosmicdrift/kumiko-dev-server": "1.0.0",
34
- "@cosmicdrift/kumiko-framework": "1.0.0",
35
- "@cosmicdrift/kumiko-server-runtime": "1.0.0",
33
+ "@cosmicdrift/kumiko-dev-server": "2.0.0",
34
+ "@cosmicdrift/kumiko-framework": "2.0.0",
35
+ "@cosmicdrift/kumiko-server-runtime": "2.0.0",
36
36
  "@inquirer/core": "^10.0.0",
37
37
  "@inquirer/prompts": "^7.4.0"
38
38
  },
@@ -8,18 +8,24 @@
8
8
  import { describe, expect, test } from "bun:test";
9
9
  import { FEATURE_CONSTRUCTORS } from "../feature-constructors";
10
10
 
11
- function expectedCallExpression(
12
- exportName: string,
13
- callArgs: readonly unknown[] | undefined,
14
- ): string {
15
- if (callArgs === undefined) {
16
- // Ambiguous by callArgs alone: could be a zero-arg factory (`fn()`) or a
17
- // bare object export (`fn`). Disambiguate the same way the runtime does
18
- // (scaffold-app.ts's instantiateScaffoldFeatures): trust the "()" the
19
- // literal itself carries, then only check the exportName prefix matches.
20
- return exportName;
11
+ // Renders a value as hand-written TS source (unquoted object keys, quoted
12
+ // string values) instead of JSON — JSON.stringify(1) and JSON.stringify("1")
13
+ // both survive a whitespace+quote-strip compare as "1", which would hide a
14
+ // string/number divergence between callExpression and callArgs. Rendering
15
+ // like this and normalizing whitespace only keeps that divergence visible.
16
+ function renderTsLiteral(value: unknown): string {
17
+ if (Array.isArray(value)) return `[${value.map(renderTsLiteral).join(", ")}]`;
18
+ if (value !== null && typeof value === "object") {
19
+ const entries = Object.entries(value as Record<string, unknown>).map(
20
+ ([key, val]) => `${key}: ${renderTsLiteral(val)}`,
21
+ );
22
+ return `{ ${entries.join(", ")} }`;
21
23
  }
22
- const args = callArgs.map((a) => JSON.stringify(a)).join(", ");
24
+ return JSON.stringify(value);
25
+ }
26
+
27
+ function expectedCallExpression(exportName: string, callArgs: readonly unknown[]): string {
28
+ const args = callArgs.map(renderTsLiteral).join(", ");
23
29
  return `${exportName}(${args})`;
24
30
  }
25
31
 
@@ -27,10 +33,10 @@ describe("FEATURE_CONSTRUCTORS callExpression/callArgs consistency", () => {
27
33
  for (const [name, entry] of Object.entries(FEATURE_CONSTRUCTORS)) {
28
34
  test(`${name}: callExpression matches exportName + callArgs`, () => {
29
35
  if (entry.callArgs !== undefined) {
30
- // callExpression is hand-formatted TS source (`{ scopes: {} }`), not
31
- // JSON (`{"scopes":{}}`)compare with whitespace stripped so both
32
- // are checked against the same underlying arg values.
33
- const normalize = (s: string) => s.replace(/[\s"]+/g, "");
36
+ // callExpression is hand-formatted TS source; compare with
37
+ // whitespace stripped only NOT quotes, so a string arg ("1") vs.
38
+ // a number arg (1) still diverges after normalize.
39
+ const normalize = (s: string) => s.replace(/\s+/g, "");
34
40
  expect(normalize(entry.callExpression)).toBe(
35
41
  normalize(expectedCallExpression(entry.exportName, entry.callArgs)),
36
42
  );
@@ -52,11 +52,9 @@ describe("--yes resolved set boots (issue-1174 regression)", () => {
52
52
  });
53
53
 
54
54
  test("the resolved --yes feature set boots without the GDPR PII-hook-coverage error", async () => {
55
- // sessions (auto-included, session-list/detail screens are recommended)
56
- // requires auth-foundation, which the dep-resolver already pulls in
57
- // transitively — personal-access-tokens (recommended, satisfies the
58
- // tokenVerifier boot invariant) is resolved into the set too.
59
- expect(resolved.featureNames).toContain("personal-access-tokens");
55
+ // sessions (auto-included) pulls auth-foundation; #1570 allows zero
56
+ // tokenVerifier when sessionStore is mounted PAT stays opt-in (#1514).
57
+ expect(resolved.featureNames).not.toContain("personal-access-tokens");
60
58
  const instances = await instantiateResolved(resolved.featureNames);
61
59
  const composed = composeFeatures(instances, { includeBundled: true });
62
60
  expect(() => validateBoot(composed)).not.toThrow();
@@ -54,6 +54,14 @@ export const FEATURE_CONSTRUCTORS: Readonly<Record<string, ScaffoldFeatureEntry>
54
54
  exportName: "createAuthEmailPasswordFeature",
55
55
  callExpression: "createAuthEmailPasswordFeature()",
56
56
  },
57
+ // Only meaningful alongside auth.signup — composeFeatures auto-mounts it
58
+ // when signup is set; listed so scaffolds can pick it explicitly (#1521).
59
+ "auth-self-registration": {
60
+ name: "auth-self-registration",
61
+ importPath: "@cosmicdrift/kumiko-bundled-features/auth-email-password",
62
+ exportName: "createAuthSelfRegistrationToggleFeature",
63
+ callExpression: "createAuthSelfRegistrationToggleFeature()",
64
+ },
57
65
  "user-profile": {
58
66
  name: "user-profile",
59
67
  importPath: "@cosmicdrift/kumiko-bundled-features/user-profile",