@krizaka/app-config 0.0.0-stage → 0.1.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 +202 -0
- package/README.md +15 -2
- package/contract/app-config.schema.json +56 -0
- package/contract/krizaka-app-config-schema.sql +57 -0
- package/dist/chunk-D3DIU5IW.js +152 -0
- package/dist/chunk-D3DIU5IW.js.map +1 -0
- package/dist/client.d.ts +83 -0
- package/dist/client.js +142 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +31 -0
- package/dist/react.js +35 -0
- package/dist/react.js.map +1 -0
- package/dist/server.d.ts +63 -0
- package/dist/server.js +176 -0
- package/dist/server.js.map +1 -0
- package/package.json +120 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/server.ts"],"sourcesContent":["/**\n * The tables of the contract, for a Next.js backend's own migration. The same DDL ships with the Java building block\n * (`krizaka-app-config-schema.sql`, copied verbatim to `contract/` and checked by a test): one schema, whichever stack\n * serves it. Version 1 is seeded permissive (no minimum, no maintenance, one contract).\n */\nexport const schemaSql = `-- krizaka-app-config: the parameters of the app-version contract, one row per platform.\n-- Version 1 is seeded here (permissive: no minimum, no maintenance, one contract); a product's own\n-- migration publishes its real values through the admin API, never by editing the row by hand.\nCREATE TABLE IF NOT EXISTS app_config (\n platform VARCHAR(16) PRIMARY KEY,\n min_supported_version VARCHAR(32) NOT NULL DEFAULT '0.0.0',\n latest_version VARCHAR(32) NOT NULL DEFAULT '0.0.0',\n update_override VARCHAR(8),\n store_url TEXT,\n maintenance_on BOOLEAN NOT NULL DEFAULT FALSE,\n maintenance_message JSONB NOT NULL DEFAULT '{}'::jsonb,\n message JSONB NOT NULL DEFAULT '{}'::jsonb,\n contract_min INTEGER NOT NULL DEFAULT 1,\n contract_max INTEGER NOT NULL DEFAULT 1,\n contract_sunset DATE,\n flags JSONB NOT NULL DEFAULT '{}'::jsonb,\n revision INTEGER NOT NULL DEFAULT 1,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n updated_by VARCHAR(255) NOT NULL DEFAULT 'seed',\n CONSTRAINT app_config_platform_known CHECK (platform IN ('ios', 'android', 'macos', 'windows', 'linux', 'web')),\n CONSTRAINT app_config_contract_range CHECK (contract_min >= 1 AND contract_max >= contract_min)\n);\n\n-- Every published revision, append-only: the audit trail and the source of a rollback.\nCREATE TABLE IF NOT EXISTS app_config_history (\n id BIGSERIAL PRIMARY KEY,\n platform VARCHAR(16) NOT NULL,\n revision INTEGER NOT NULL,\n min_supported_version VARCHAR(32) NOT NULL,\n latest_version VARCHAR(32) NOT NULL,\n update_override VARCHAR(8),\n store_url TEXT,\n maintenance_on BOOLEAN NOT NULL,\n maintenance_message JSONB NOT NULL,\n message JSONB NOT NULL,\n contract_min INTEGER NOT NULL,\n contract_max INTEGER NOT NULL,\n contract_sunset DATE,\n flags JSONB NOT NULL,\n reason TEXT NOT NULL,\n changed_by VARCHAR(255) NOT NULL,\n changed_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n CONSTRAINT app_config_history_revision UNIQUE (platform, revision)\n);\n\nINSERT INTO app_config (platform)\nVALUES ('ios'), ('android'), ('macos'), ('windows'), ('linux'), ('web')\nON CONFLICT (platform) DO NOTHING;\n\nINSERT INTO app_config_history (platform, revision, min_supported_version, latest_version, update_override,\n store_url, maintenance_on, maintenance_message, message, contract_min,\n contract_max, contract_sunset, flags, reason, changed_by, changed_at)\nSELECT platform, revision, min_supported_version, latest_version, update_override, store_url, maintenance_on,\n maintenance_message, message, contract_min, contract_max, contract_sunset, flags, 'seed', updated_by,\n updated_at\nFROM app_config\nON CONFLICT (platform, revision) DO NOTHING;\n`;\n","import {\n APP_CONFIG_PATH,\n type AppConfigRecord,\n buildPayload,\n CLIENT_HEADERS,\n defaultRecord,\n evaluateGuard,\n type GuardResult,\n parseVersion,\n type Platform,\n toPlatform,\n} from \"./core\";\n\nexport { schemaSql } from \"./schema\";\n\n/** Where a Next.js backend keeps the parameters; the tables are `schemaSql`. */\nexport interface AppConfigStore {\n get(platform: Platform): Promise<AppConfigRecord | undefined>;\n}\n\n/** A store over fixed records: tests and demos. */\nexport function memoryStore(records: readonly AppConfigRecord[] = []): AppConfigStore {\n const byPlatform = new Map(records.map((r) => [r.platform, r]));\n return { get: async (platform) => byPlatform.get(platform) };\n}\n\nexport interface CacheOptions {\n /** How long a read value is reused. */\n ttlMs: number;\n now?: () => number;\n}\n\n/**\n * Reads through a short cache and never lets the store take the API down: on a failure the last value is\n * served, and with none the permissive defaults.\n */\nexport function cachedStore(store: AppConfigStore, { ttlMs, now = Date.now }: CacheOptions): AppConfigStore & { evict(platform?: Platform): void } {\n const cache = new Map<Platform, { record: AppConfigRecord; at: number }>();\n return {\n evict: (platform) => (platform ? cache.delete(platform) : cache.clear()),\n async get(platform) {\n const hit = cache.get(platform);\n if (hit && now() - hit.at < ttlMs) return hit.record;\n try {\n const record = (await store.get(platform)) ?? defaultRecord(platform);\n cache.set(platform, { record, at: now() });\n return record;\n } catch {\n return hit?.record ?? defaultRecord(platform);\n }\n },\n };\n}\n\nasync function etagOf(text: string): Promise<string> {\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(text));\n const hex = Array.from(new Uint8Array(digest).slice(0, 12), (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `\"${hex}\"`;\n}\n\nfunction problem(status: number, code: string, detail: string): Response {\n return Response.json({ title: \"Bad Request\", status, code, detail }, { status, headers: { \"content-type\": \"application/problem+json\" } });\n}\n\nfunction languageOf(header: string | null): string | null {\n const first = (header ?? \"\").split(\",\", 1).join(\"\").trim();\n return first.length >= 2 ? first.slice(0, 2) : null;\n}\n\nexport interface HandlerOptions {\n store: AppConfigStore;\n /** The public `max-age`, seconds. Defaults to 60. */\n maxAgeSeconds?: number;\n}\n\n/**\n * `GET /api/v1/app-config` for a route handler: public, cacheable, `ETag`, `304`. Mount it at\n * `app/api/v1/app-config/route.ts`: `export const GET = createAppConfigHandler({ store })`.\n */\nexport function createAppConfigHandler({ store, maxAgeSeconds = 60 }: HandlerOptions): (request: Request) => Promise<Response> {\n return async (request) => {\n const url = new URL(request.url);\n const platform = toPlatform(url.searchParams.get(\"platform\") ?? request.headers.get(CLIENT_HEADERS.platform));\n if (!platform) return problem(400, \"unknown-platform\", \"platform must be one of ios, android, macos, windows, linux, web.\");\n const versionText = url.searchParams.get(\"version\");\n const version = versionText ? parseVersion(versionText) : null;\n if (versionText && !version) return problem(400, \"invalid-version\", \"version must look like 1.4.0.\");\n const language = url.searchParams.get(\"locale\") ?? languageOf(request.headers.get(\"accept-language\"));\n const record = (await store.get(platform)) ?? defaultRecord(platform);\n const payload = buildPayload(record, version, language);\n const body = JSON.stringify(payload);\n const etag = await etagOf(body);\n const headers = {\n \"cache-control\": `public, max-age=${maxAgeSeconds}, stale-while-revalidate=${maxAgeSeconds * 5}`,\n etag,\n vary: \"Accept-Language\",\n [CLIENT_HEADERS.contract]: String(payload.contract.max),\n };\n if (request.headers.get(\"if-none-match\") === etag) return new Response(null, { status: 304, headers });\n return new Response(body, { status: 200, headers: { ...headers, \"content-type\": \"application/json\" } });\n };\n}\n\n/** What the guard decided, ready to apply to a response. */\nexport interface GuardOutcome {\n /** The `426` to return, or `null` to continue. */\n refusal: Response | null;\n /** `X-Contract-Version`, `Deprecation`, `Sunset` — set them on the response you return. */\n headers: Record<string, string>;\n result: GuardResult | null;\n}\n\nexport interface GuardOptions {\n store: AppConfigStore;\n /** The base of Problem Details `type`. Defaults to `https://krizaka.com/problems/`. */\n problemBase?: string;\n}\n\n/**\n * The `426 Upgrade Required` filter for a Next.js backend (a route handler, or the proxy/middleware). A request\n * without `X-Client-Platform` is not an app and passes untouched.\n */\nexport async function checkClientVersion(request: Request, { store, problemBase = \"https://krizaka.com/problems/\" }: GuardOptions): Promise<GuardOutcome> {\n const platform = toPlatform(request.headers.get(CLIENT_HEADERS.platform));\n if (!platform) return { refusal: null, headers: {}, result: null };\n const record = (await store.get(platform)) ?? defaultRecord(platform);\n const result = evaluateGuard(record, {\n platform,\n version: request.headers.get(CLIENT_HEADERS.version),\n contract: request.headers.get(CLIENT_HEADERS.contract),\n language: languageOf(request.headers.get(\"accept-language\")),\n });\n const headers: Record<string, string> = { [CLIENT_HEADERS.contract]: String(result.contract) };\n if (result.deprecation) headers[CLIENT_HEADERS.deprecation] = \"true\";\n if (result.status === 200 && result.sunset) headers[CLIENT_HEADERS.sunset] = result.sunset;\n if (result.status !== 426) return { refusal: null, headers, result };\n const { code, payload } = result;\n const detail =\n code === \"contract-unsupported\"\n ? \"This version of the app speaks an API contract that is no longer served. Update the app.\"\n : \"This version of the app is no longer supported. Update the app.\";\n const refusal = new Response(\n JSON.stringify({ type: problemBase + code, title: \"Upgrade Required\", status: 426, code, detail, instance: new URL(request.url).pathname, appConfig: payload }),\n {\n status: 426,\n headers: {\n ...headers,\n \"content-type\": \"application/problem+json\",\n \"cache-control\": \"no-store\",\n upgrade: `krizaka-app/${payload.minSupportedVersion}`,\n },\n },\n );\n return { refusal, headers, result };\n}\n\n/**\n * Wraps a route handler: an app below the minimum gets the `426` before the handler runs; otherwise the\n * handler's response carries the contract headers. `APP_CONFIG_PATH` itself should not be wrapped.\n */\nexport function withClientVersionGuard<A extends unknown[]>(\n options: GuardOptions,\n handler: (request: Request, ...args: A) => Response | Promise<Response>,\n): (request: Request, ...args: A) => Promise<Response> {\n return async (request, ...args) => {\n const outcome = await checkClientVersion(request, options);\n if (outcome.refusal) return outcome.refusal;\n const response = await handler(request, ...args);\n for (const [name, value] of Object.entries(outcome.headers)) response.headers.set(name, value);\n return response;\n };\n}\n\nexport { APP_CONFIG_PATH };\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,123 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krizaka/app-config",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "App version compatibility for Krizaka apps and backends: one contract (min/latest version, update mode, maintenance, contract range, 426 Upgrade Required, N-1 with Deprecation/Sunset) for Next.js backends and mobile, desktop and web clients. Twin of the Java building block krizaka-app-config. Zero dependency.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"krizaka",
|
|
7
|
+
"app-config",
|
|
8
|
+
"force-update",
|
|
9
|
+
"version",
|
|
10
|
+
"426",
|
|
11
|
+
"expo",
|
|
12
|
+
"react-native",
|
|
13
|
+
"contract"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://ui.krizaka.com/packages/app-config",
|
|
16
|
+
"bugs": "https://github.com/krizaka/krizaka-ui/issues",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/krizaka/krizaka-ui.git",
|
|
20
|
+
"directory": "packages/app-config"
|
|
21
|
+
},
|
|
22
|
+
"license": "Apache-2.0",
|
|
23
|
+
"author": "Krizaka (https://www.krizaka.com)",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./server": {
|
|
34
|
+
"types": "./dist/server.d.ts",
|
|
35
|
+
"import": "./dist/server.js"
|
|
36
|
+
},
|
|
37
|
+
"./client": {
|
|
38
|
+
"types": "./dist/client.d.ts",
|
|
39
|
+
"import": "./dist/client.js"
|
|
40
|
+
},
|
|
41
|
+
"./react": {
|
|
42
|
+
"types": "./dist/react.d.ts",
|
|
43
|
+
"import": "./dist/react.js"
|
|
44
|
+
},
|
|
45
|
+
"./contract/app-config.schema.json": "./contract/app-config.schema.json",
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist",
|
|
50
|
+
"contract",
|
|
51
|
+
"README.md",
|
|
52
|
+
"LICENSE"
|
|
53
|
+
],
|
|
54
|
+
"sideEffects": false,
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
57
|
+
"@size-limit/preset-small-lib": "^14.2.0",
|
|
58
|
+
"@testing-library/dom": "^10.4.0",
|
|
59
|
+
"@testing-library/react": "^16.3.0",
|
|
60
|
+
"@types/node": "^22.15.0",
|
|
61
|
+
"@types/react": "^19.2.0",
|
|
62
|
+
"@types/react-dom": "^19.2.0",
|
|
63
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
64
|
+
"eslint": "^9.39.0",
|
|
65
|
+
"happy-dom": "^20.0.0",
|
|
66
|
+
"publint": "^0.3.25",
|
|
67
|
+
"react": "^19.2.0",
|
|
68
|
+
"react-dom": "^19.2.0",
|
|
69
|
+
"size-limit": "^14.2.0",
|
|
70
|
+
"tsup": "^8.5.1",
|
|
71
|
+
"typescript": "^5.9.0",
|
|
72
|
+
"vitest": "^4.1.11",
|
|
73
|
+
"@krizaka/config": "0.4.1"
|
|
74
|
+
},
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=22"
|
|
77
|
+
},
|
|
78
|
+
"publishConfig": {
|
|
79
|
+
"access": "public"
|
|
80
|
+
},
|
|
81
|
+
"size-limit": [
|
|
82
|
+
{
|
|
83
|
+
"name": ".",
|
|
84
|
+
"path": "dist/index.js",
|
|
85
|
+
"limit": "2 kB",
|
|
86
|
+
"gzip": true
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "./server",
|
|
90
|
+
"path": "dist/server.js",
|
|
91
|
+
"limit": "3.2 kB",
|
|
92
|
+
"gzip": true
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "./client",
|
|
96
|
+
"path": "dist/client.js",
|
|
97
|
+
"limit": "2 kB",
|
|
98
|
+
"gzip": true
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "./react",
|
|
102
|
+
"path": "dist/react.js",
|
|
103
|
+
"limit": "1 kB",
|
|
104
|
+
"gzip": true
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"peerDependencies": {
|
|
108
|
+
"react": ">=18"
|
|
109
|
+
},
|
|
110
|
+
"peerDependenciesMeta": {
|
|
111
|
+
"react": {
|
|
112
|
+
"optional": true
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"scripts": {
|
|
116
|
+
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsup",
|
|
117
|
+
"lint": "eslint . --max-warnings 0 && tsc --noEmit --noUnusedLocals --noUnusedParameters --noFallthroughCasesInSwitch --noImplicitReturns",
|
|
118
|
+
"typecheck": "tsc --noEmit",
|
|
119
|
+
"test": "vitest run --coverage",
|
|
120
|
+
"size": "size-limit",
|
|
121
|
+
"publint": "publint && attw --pack . --profile esm-only"
|
|
122
|
+
}
|
|
6
123
|
}
|