@ultimat3/pwa 17.0.0 → 18.0.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/CLAUDE.md +3 -1
- package/README.md +11 -2
- package/package.json +4 -4
- package/src/index.ts +1 -3
- package/src/manifest.ts +17 -16
package/CLAUDE.md
CHANGED
|
@@ -13,6 +13,7 @@ Tier 4. May import tiers 0–3: `core`, `schema`, `i18n`, `money`, `time`, `cach
|
|
|
13
13
|
| Determinism | no `Date.now()`, no randomness, sort every collection. Same input → same bytes. `subscriptionState` took `now = Date.now()` and was the one exception; it takes a `Clock` `As of 2026-08-23`, so a frozen clock freezes this package too. |
|
|
14
14
|
| Rule ORDER | most specific first, then the path. `ruleFor` in the emitted worker returns the FIRST pattern that matches and has no notion of specificity, so the sort IS the routing decision. Alphabetical, `:` (0x3A) and `*` (0x2A) sort before every letter: `/posts/:id` shadowed `/posts/new`, and one `/*` catch-all shadowed the whole table — every `PRECACHE_MANIFEST` entry downloaded at install and never looked up, and a cacheable route served `network-only`, which offline is the `/offline` document. Weights are `@ultimat3/render`'s `compilePattern` (literal 100, `:param` 10, `*` 1), **duplicated** because both packages are tier 4; a wildcard sorts last outright, because a sum over segments cannot say that `/` (0 segments) outranks `/*rest` (1). The shared home is `@ultimat3/core`'s `route-vocabulary.ts`. |
|
|
15
15
|
| A generated header | names something that regenerates the file. `sw.js` said `regenerate: x build` and no `x build` target emits a service worker — `generateServiceWorker` has no caller anywhere in the tree — so it names the CALL until a build writes it. |
|
|
16
|
+
| What is WIRED, and what is not | `generateWebManifest`, `renderThemeColorMeta`, `planIcons`, `appleTouchLinks` and `BuiltinImagePipeline` are called by `@ultimat3/cli` (`pwa-artifacts.ts`, `dev-assets.ts`), so `x dev`, the container and the static export all emit `manifest.webmanifest` and the `<head>` that names it, `As of 2026-08-27`. `generateServiceWorker`, `buildPrecacheManifest`, `offlineFallbackSource`, `backgroundSyncSource` and `pushSource` still have **zero** callers outside this package (#362) — a bad `sw.js` is sticky and nothing in the gate can drive a real service worker, so the worker lands behind a real browser check rather than beside the manifest. |
|
|
16
17
|
| Route input | `PwaRoute` is a **structural** view of render's `RouteDescriptor`. Never import render. |
|
|
17
18
|
| Strategy choice | derived from render mode via `MODE_STRATEGY`. Per-route override only. |
|
|
18
19
|
| Precache revision | content hash. Never the build id — that re-downloads everything per deploy. |
|
|
@@ -30,7 +31,8 @@ Tier 4. May import tiers 0–3: `core`, `schema`, `i18n`, `money`, `time`, `cach
|
|
|
30
31
|
| Outbox | queue lives in `@ultimat3/realtime`. This package only registers the sync trigger — and schedules **no retry**: the handler rejects and the PLATFORM decides when to wake it again. `RetryPolicy`, `DEFAULT_RETRY`, `retryDelayMs`, `shouldRetry` and `BackgroundSyncOptions.retry` were deleted 2026-08-23; of the policy only `maxAttempts` ever reached the worker, as a `SYNC_MAX_ATTEMPTS` constant nothing read, and the emitted `X_PWA_SYNC_INCOMPLETE` fix told the reader to raise `pwa.backgroundSync.retry.maxAttempts`, a key `PwaConfig` has never had. `background-sync.test.ts` asserts that every constant the worker declares is one the worker reads. |
|
|
31
32
|
| Push strings | i18n keys only, rendered per subscriber locale. Never a literal. |
|
|
32
33
|
| Push URLs | `PushPayload.url` is a PATH and `WindowClient.url` is absolute, so `notificationclick` resolves against `self.location.origin` before comparing. Unresolved, the focus-existing-tab loop matched nothing and every tap opened a second window. |
|
|
33
|
-
| Colours |
|
|
34
|
+
| Colours | `@ultimat3/core`'s `PwaColors`, passed in as `WebManifestInput.tokens`. Never a hex literal in this package — a test fixture asserting the parser is the one exception. This package declared `ThemeTokens`/`SchemeColors` itself until 2026-08-27: structurally identical to what `app.config.ts` already carried, with no map between them and nothing asserting they agreed, which is the axiom-1 defect the two `PwaConfig`s were. Deleted; tier 0 owns the shape. |
|
|
35
|
+
| `WebManifestInput` | what `generateWebManifest` takes, and **not** the `pwa` block of `app.config.ts` — it was called `PwaConfig` and said it was, while `@ultimat3/core` exported a different type of the same name that really is the block. An app declares `name` and `colors`; every other member is a caller's (`icons` from `planIcons`, `capabilities` from the build). `packages/cli/src/pwa-artifacts.ts` is the one composer of the two, and the only caller of `generateWebManifest` in the tree. |
|
|
34
36
|
| Icons | one source image → `BuiltinImagePipeline` → a square PNG per `ICON_MATRIX` entry, rendered by `@ultimat3/core`'s image pipeline. Never a second scaler, never `sharp`, never a vendor CDN. |
|
|
35
37
|
| Icon source | a **PNG** (core decodes PNG and JPEG only). `x new` scaffolds one; `@ultimat3/cli`'s `dev-assets.ts` reads it at `ICON_SOURCE` and serves every entry at its `outputPath`. This package renders bytes and mounts nothing. |
|
|
36
38
|
| Icon background | `IconSourceConfig.background`, hex or `transparent` — core's grammar has no named colours. Default transparent. |
|
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ capability nothing implements.
|
|
|
89
89
|
| `strategyFor`, `MODE_STRATEGY`, `cacheFirst`, … | the four strategies + the mapping table |
|
|
90
90
|
| `buildPrecacheManifest` | precache entries (url + content-hash revision), size warnings |
|
|
91
91
|
| `buildId`, `detectSkew`, `retentionPlan` | version skew |
|
|
92
|
-
| `generateWebManifest` | the manifest + `theme-color` metas for both schemes |
|
|
92
|
+
| `generateWebManifest` | the manifest + `theme-color` metas for both schemes, from a `WebManifestInput`. Called by `@ultimat3/cli` (`pwa-artifacts.ts`) `As of 2026-08-27`, so `x dev`, the container and the static export all emit `manifest.webmanifest` |
|
|
93
93
|
| `planIcons`, `requireSourceIcon`, `maskableSafeZone` | icons and splashes from one source |
|
|
94
94
|
| `BuiltinImagePipeline` | renders that plan: one square PNG per entry, deterministic |
|
|
95
95
|
| `requireOfflineFallback` | the mandatory offline route |
|
|
@@ -103,7 +103,16 @@ capability nothing implements.
|
|
|
103
103
|
- **Theme colours come from the design tokens for both schemes.** The manifest spec carries
|
|
104
104
|
one `theme_color`, so the dark value is emitted as a media-scoped
|
|
105
105
|
`<meta name="theme-color">` — otherwise an installed dark app launches with a light status
|
|
106
|
-
bar every time.
|
|
106
|
+
bar every time. The shape is `@ultimat3/core`'s `PwaColors`, which is what an app writes in
|
|
107
|
+
`app.config.ts` as `pwa.colors`; this package declared its own identical `ThemeTokens` until
|
|
108
|
+
2026-08-27, with nothing asserting the two agreed.
|
|
109
|
+
- **`WebManifestInput` is not the `pwa` block of `app.config.ts`.** It was called `PwaConfig` and
|
|
110
|
+
said it was, while `@ultimat3/core` exported a different type of that name that really is the
|
|
111
|
+
block. An app writes `name` and `colors`; every other member is a caller's.
|
|
112
|
+
- **The service worker still has no build behind it, `As of 2026-08-27`.** `generateServiceWorker`,
|
|
113
|
+
`buildPrecacheManifest`, `offlineFallbackSource`, `backgroundSyncSource` and `pushSource` have no
|
|
114
|
+
caller outside this package ([#362](https://github.com/developerz-ai/ultimate/issues/362)) — the
|
|
115
|
+
manifest half is wired, the worker half is not.
|
|
107
116
|
- **Precache revisions are content hashes, never the build id.** Keying on the build id
|
|
108
117
|
re-downloads every asset on every deploy.
|
|
109
118
|
- **The mutation queue lives in `@ultimat3/realtime`, not here** (SRP). This package owns
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/pwa",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.0",
|
|
4
4
|
"description": "Generated service worker, web manifest, icons, push and version-skew handling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"LICENSE"
|
|
25
25
|
],
|
|
26
26
|
"engines": {
|
|
27
|
-
"bun": ">=1.
|
|
27
|
+
"bun": ">=1.4.0"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
31
31
|
"test": "bun test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ultimat3/core": "
|
|
35
|
-
"@ultimat3/seo": "
|
|
34
|
+
"@ultimat3/core": "18.0.0",
|
|
35
|
+
"@ultimat3/seo": "18.0.0"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/index.ts
CHANGED
|
@@ -79,12 +79,10 @@ export type {
|
|
|
79
79
|
ManifestShortcut,
|
|
80
80
|
Orientation,
|
|
81
81
|
ProtocolHandler,
|
|
82
|
-
PwaConfig,
|
|
83
|
-
SchemeColors,
|
|
84
82
|
ShareTarget,
|
|
85
83
|
ThemeColorMeta,
|
|
86
|
-
ThemeTokens,
|
|
87
84
|
WebManifest,
|
|
85
|
+
WebManifestInput,
|
|
88
86
|
WebManifestResult,
|
|
89
87
|
} from './manifest';
|
|
90
88
|
export { generateWebManifest, renderThemeColorMeta, serializeWebManifest } from './manifest';
|
package/src/manifest.ts
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* app gets a light status bar on every launch.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// `PwaColors`/`PwaSchemeColors` are tier 0's, not this package's. They were declared here as
|
|
9
|
+
// `ThemeTokens`/`SchemeColors` — structurally identical to what `app.config.ts` already carried,
|
|
10
|
+
// with no map between them and nothing asserting they agreed, which is the same axiom-1 defect the
|
|
11
|
+
// two `PwaConfig`s were. An app writes them once, in the one config file.
|
|
12
|
+
import type { PwaColors } from '@ultimat3/core';
|
|
8
13
|
import { escapeAttribute } from '@ultimat3/seo';
|
|
9
14
|
import type { CapabilityFlags, ResolvedCapabilities } from './capabilities';
|
|
10
15
|
import { isEnabled, resolveCapabilities } from './capabilities';
|
|
@@ -81,19 +86,15 @@ export interface WebManifest {
|
|
|
81
86
|
readonly protocol_handlers?: readonly ProtocolHandler[];
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** The `pwa` block of `app.config.ts`. */
|
|
96
|
-
export interface PwaConfig {
|
|
89
|
+
/**
|
|
90
|
+
* Everything `generateWebManifest` needs, which is NOT the `pwa` block of `app.config.ts` — this
|
|
91
|
+
* type was called `PwaConfig` and said it was, while `@ultimat3/core` exported a different type of
|
|
92
|
+
* the same name that really is the block. Two exported `PwaConfig`s with no map between them is
|
|
93
|
+
* axiom 1, and the one that lied is this one: an app declares `name` and `colors`, and every other
|
|
94
|
+
* member here is a caller's — `icons` comes from `planIcons`, `capabilities` from the build.
|
|
95
|
+
* `packages/cli/src/pwa-artifacts.ts` is what composes the two into this.
|
|
96
|
+
*/
|
|
97
|
+
export interface WebManifestInput {
|
|
97
98
|
readonly name: string;
|
|
98
99
|
readonly shortName?: string;
|
|
99
100
|
readonly description?: string;
|
|
@@ -104,7 +105,7 @@ export interface PwaConfig {
|
|
|
104
105
|
readonly orientation?: Orientation;
|
|
105
106
|
readonly lang?: string;
|
|
106
107
|
readonly dir?: 'ltr' | 'rtl' | 'auto';
|
|
107
|
-
readonly tokens:
|
|
108
|
+
readonly tokens: PwaColors;
|
|
108
109
|
readonly categories?: readonly string[];
|
|
109
110
|
readonly icons?: readonly ManifestIcon[];
|
|
110
111
|
readonly shortcuts?: readonly ManifestShortcut[];
|
|
@@ -127,7 +128,7 @@ export interface WebManifestResult {
|
|
|
127
128
|
readonly capabilities: ResolvedCapabilities;
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
export function generateWebManifest(config:
|
|
131
|
+
export function generateWebManifest(config: WebManifestInput): WebManifestResult {
|
|
131
132
|
assertValid(config);
|
|
132
133
|
const capabilities = resolveCapabilities(config.capabilities);
|
|
133
134
|
const scope = config.scope ?? '/';
|
|
@@ -178,7 +179,7 @@ export function generateWebManifest(config: PwaConfig): WebManifestResult {
|
|
|
178
179
|
|
|
179
180
|
type MutableManifest = { -readonly [K in keyof WebManifest]?: WebManifest[K] };
|
|
180
181
|
|
|
181
|
-
function assertValid(config:
|
|
182
|
+
function assertValid(config: WebManifestInput): void {
|
|
182
183
|
if (config.name.trim() === '') {
|
|
183
184
|
throw new PwaManifestInvalidError(
|
|
184
185
|
'pwa.name is empty, so the install prompt would have no title',
|