@nifrajs/core 2.0.0 → 2.2.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/README.md +27 -0
- package/dist/capabilities.d.ts +54 -2
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +240 -5
- package/dist/capabilities.js.map +1 -1
- package/dist/durable-adapters.d.ts +241 -0
- package/dist/durable-adapters.d.ts.map +1 -0
- package/dist/durable-adapters.js +697 -0
- package/dist/durable-adapters.js.map +1 -0
- package/dist/durable-execution.d.ts +349 -0
- package/dist/durable-execution.d.ts.map +1 -0
- package/dist/durable-execution.js +1173 -0
- package/dist/durable-execution.js.map +1 -0
- package/dist/effect-lifecycle.d.ts +42 -0
- package/dist/effect-lifecycle.d.ts.map +1 -0
- package/dist/effect-lifecycle.js +66 -0
- package/dist/effect-lifecycle.js.map +1 -0
- package/dist/effect-scope.d.ts +75 -0
- package/dist/effect-scope.d.ts.map +1 -0
- package/dist/effect-scope.js +177 -0
- package/dist/effect-scope.js.map +1 -0
- package/dist/idempotency-plugin.d.ts +5 -0
- package/dist/idempotency-plugin.d.ts.map +1 -1
- package/dist/idempotency-plugin.js +8 -0
- package/dist/idempotency-plugin.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/capability-runtime.d.ts +62 -1
- package/dist/internal/capability-runtime.d.ts.map +1 -1
- package/dist/internal/capability-runtime.js +11 -2
- package/dist/internal/capability-runtime.js.map +1 -1
- package/dist/internal/effect-execution.d.ts +16 -0
- package/dist/internal/effect-execution.d.ts.map +1 -0
- package/dist/internal/effect-execution.js +50 -0
- package/dist/internal/effect-execution.js.map +1 -0
- package/dist/internal/safe-equal.d.ts +20 -0
- package/dist/internal/safe-equal.d.ts.map +1 -0
- package/dist/internal/safe-equal.js +31 -0
- package/dist/internal/safe-equal.js.map +1 -0
- package/dist/ledger.d.ts +14 -6
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +31 -5
- package/dist/ledger.js.map +1 -1
- package/dist/reconciliation-worker.d.ts +108 -0
- package/dist/reconciliation-worker.d.ts.map +1 -0
- package/dist/reconciliation-worker.js +239 -0
- package/dist/reconciliation-worker.js.map +1 -0
- package/dist/router/pattern.d.ts +26 -1
- package/dist/router/pattern.d.ts.map +1 -1
- package/dist/router/pattern.js +164 -8
- package/dist/router/pattern.js.map +1 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +49 -1
- package/dist/router/router.js.map +1 -1
- package/dist/server/idempotency-lane.d.ts +1 -0
- package/dist/server/idempotency-lane.d.ts.map +1 -1
- package/dist/server/idempotency-lane.js +61 -37
- package/dist/server/idempotency-lane.js.map +1 -1
- package/dist/server/respond.d.ts.map +1 -1
- package/dist/server/respond.js.map +1 -1
- package/dist/server/server.d.ts +12 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +33 -2
- package/dist/server/server.js.map +1 -1
- package/dist/server/transport-lane.d.ts +28 -0
- package/dist/server/transport-lane.d.ts.map +1 -0
- package/dist/server/transport-lane.js +106 -0
- package/dist/server/transport-lane.js.map +1 -0
- package/dist/server/websocket.d.ts +6 -0
- package/dist/server/websocket.d.ts.map +1 -1
- package/dist/server/websocket.js +10 -1
- package/dist/server/websocket.js.map +1 -1
- package/dist/transport-codec-rich.d.ts +8 -0
- package/dist/transport-codec-rich.d.ts.map +1 -0
- package/dist/transport-codec-rich.js +14 -0
- package/dist/transport-codec-rich.js.map +1 -0
- package/dist/transport-codec.d.ts +31 -0
- package/dist/transport-codec.d.ts.map +1 -0
- package/dist/transport-codec.js +214 -0
- package/dist/transport-codec.js.map +1 -0
- package/dist/transport-plugin.d.ts +3 -0
- package/dist/transport-plugin.d.ts.map +1 -0
- package/dist/transport-plugin.js +3 -0
- package/dist/transport-plugin.js.map +1 -0
- package/dist/wire.d.ts +58 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +445 -0
- package/dist/wire.js.map +1 -0
- package/package.json +46 -1
- package/src/capabilities.ts +306 -5
- package/src/durable-adapters.ts +1039 -0
- package/src/durable-execution.ts +1676 -0
- package/src/effect-lifecycle.ts +120 -0
- package/src/effect-scope.ts +267 -0
- package/src/idempotency-plugin.ts +10 -0
- package/src/index.ts +1 -1
- package/src/internal/capability-runtime.ts +87 -1
- package/src/internal/effect-execution.ts +70 -0
- package/src/internal/safe-equal.ts +27 -0
- package/src/ledger.ts +45 -11
- package/src/reconciliation-worker.ts +372 -0
- package/src/router/pattern.ts +179 -8
- package/src/router/router.ts +75 -1
- package/src/server/idempotency-lane.ts +68 -34
- package/src/server/respond.ts +1 -0
- package/src/server/server.ts +46 -0
- package/src/server/transport-lane.ts +141 -0
- package/src/server/websocket.ts +15 -1
- package/src/transport-codec-rich.ts +20 -0
- package/src/transport-codec.ts +284 -0
- package/src/transport-plugin.ts +2 -0
- package/src/wire.ts +474 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/** Leased, cursor-checkpointed, bounded reconciliation worker orchestration. */
|
|
2
|
+
import { reconcileEffectsPage, reconcileSagasPage, } from "./durable-execution.js";
|
|
3
|
+
import { safeEqual } from "./internal/safe-equal.js";
|
|
4
|
+
const TOKEN = /^[!-~]{1,128}$/;
|
|
5
|
+
function positive(value, label, max) {
|
|
6
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > max)
|
|
7
|
+
throw new RangeError(`${label} must be an integer between 1 and ${max}`);
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function timestamp(value) {
|
|
11
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
12
|
+
throw new RangeError("reconciliation clock must return a non-negative safe integer");
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function assertToken(value, label) {
|
|
16
|
+
if (!TOKEN.test(value))
|
|
17
|
+
throw new TypeError(`${label} must be a bounded printable token`);
|
|
18
|
+
}
|
|
19
|
+
function throwIfAborted(signal) {
|
|
20
|
+
if (signal.aborted)
|
|
21
|
+
throw signal.reason instanceof Error ? signal.reason : new Error("reconciliation aborted");
|
|
22
|
+
}
|
|
23
|
+
async function boundedMap(values, concurrency, run) {
|
|
24
|
+
let next = 0;
|
|
25
|
+
const worker = async () => {
|
|
26
|
+
for (;;) {
|
|
27
|
+
const index = next++;
|
|
28
|
+
if (index >= values.length)
|
|
29
|
+
return;
|
|
30
|
+
await run(values[index]);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, () => worker()));
|
|
34
|
+
}
|
|
35
|
+
export async function runReconciliationWorker(options) {
|
|
36
|
+
assertToken(options.name, "reconciliation worker name");
|
|
37
|
+
assertToken(options.owner, "reconciliation worker owner");
|
|
38
|
+
const leaseMs = positive(options.leaseMs ?? 30_000, "reconciliation leaseMs", 86_400_000);
|
|
39
|
+
const batchSize = positive(options.batchSize ?? 100, "reconciliation batchSize", 1_000);
|
|
40
|
+
const maxPages = positive(options.maxPages ?? 10, "reconciliation maxPages", 1_000);
|
|
41
|
+
const concurrency = positive(options.concurrency ?? 4, "reconciliation concurrency", 64);
|
|
42
|
+
const now = options.now ?? Date.now;
|
|
43
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
44
|
+
throwIfAborted(signal);
|
|
45
|
+
const lease = await options.leases.acquire({
|
|
46
|
+
name: options.name,
|
|
47
|
+
owner: options.owner,
|
|
48
|
+
now: timestamp(now()),
|
|
49
|
+
leaseMs,
|
|
50
|
+
});
|
|
51
|
+
if (lease === undefined)
|
|
52
|
+
return { acquired: false, pages: 0, scanned: 0, handled: 0 };
|
|
53
|
+
if (lease.name !== options.name ||
|
|
54
|
+
lease.owner !== options.owner ||
|
|
55
|
+
!TOKEN.test(lease.token) ||
|
|
56
|
+
!Number.isSafeInteger(lease.expiresAt) ||
|
|
57
|
+
lease.expiresAt <= 0 ||
|
|
58
|
+
(lease.cursor !== undefined && !/^[ -~]{1,1024}$/u.test(lease.cursor))) {
|
|
59
|
+
throw new TypeError("reconciliation lease store returned an invalid lease");
|
|
60
|
+
}
|
|
61
|
+
options.observe?.({ type: "acquired", name: options.name });
|
|
62
|
+
let cursor = lease.cursor;
|
|
63
|
+
let pages = 0;
|
|
64
|
+
let scanned = 0;
|
|
65
|
+
let handled = 0;
|
|
66
|
+
try {
|
|
67
|
+
while (pages < maxPages) {
|
|
68
|
+
throwIfAborted(signal);
|
|
69
|
+
const renewed = await options.leases.renew({
|
|
70
|
+
name: options.name,
|
|
71
|
+
owner: options.owner,
|
|
72
|
+
token: lease.token,
|
|
73
|
+
now: timestamp(now()),
|
|
74
|
+
leaseMs,
|
|
75
|
+
});
|
|
76
|
+
if (!renewed) {
|
|
77
|
+
options.observe?.({ type: "lease-lost", name: options.name });
|
|
78
|
+
throw new Error("reconciliation lease lost");
|
|
79
|
+
}
|
|
80
|
+
let page;
|
|
81
|
+
try {
|
|
82
|
+
page = await options.scan({
|
|
83
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
84
|
+
limit: batchSize,
|
|
85
|
+
signal,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
options.observe?.({ type: "failed", name: options.name, errorCode: "scan" });
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
if (!Array.isArray(page.findings) || page.findings.length > batchSize)
|
|
93
|
+
throw new TypeError("reconciliation scan returned an invalid or oversized page");
|
|
94
|
+
pages++;
|
|
95
|
+
scanned += page.findings.length;
|
|
96
|
+
const selected = options.filter === undefined ? page.findings : page.findings.filter(options.filter);
|
|
97
|
+
try {
|
|
98
|
+
await boundedMap(selected, concurrency, async (finding) => {
|
|
99
|
+
throwIfAborted(signal);
|
|
100
|
+
await options.handle(finding, signal);
|
|
101
|
+
handled++;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
options.observe?.({ type: "failed", name: options.name, errorCode: "handle" });
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
const renewedAfterWork = await options.leases.renew({
|
|
109
|
+
name: options.name,
|
|
110
|
+
owner: options.owner,
|
|
111
|
+
token: lease.token,
|
|
112
|
+
now: timestamp(now()),
|
|
113
|
+
leaseMs,
|
|
114
|
+
});
|
|
115
|
+
if (!renewedAfterWork) {
|
|
116
|
+
options.observe?.({ type: "lease-lost", name: options.name });
|
|
117
|
+
throw new Error("reconciliation lease expired during page handling");
|
|
118
|
+
}
|
|
119
|
+
options.observe?.({
|
|
120
|
+
type: "page",
|
|
121
|
+
name: options.name,
|
|
122
|
+
scanned: page.findings.length,
|
|
123
|
+
handled: selected.length,
|
|
124
|
+
});
|
|
125
|
+
const checkpointed = await options.leases.checkpoint({
|
|
126
|
+
name: options.name,
|
|
127
|
+
owner: options.owner,
|
|
128
|
+
token: lease.token,
|
|
129
|
+
...(page.cursor === undefined ? {} : { cursor: page.cursor }),
|
|
130
|
+
});
|
|
131
|
+
if (!checkpointed) {
|
|
132
|
+
options.observe?.({ type: "lease-lost", name: options.name });
|
|
133
|
+
throw new Error("reconciliation lease lost before checkpoint");
|
|
134
|
+
}
|
|
135
|
+
options.observe?.({
|
|
136
|
+
type: "checkpoint",
|
|
137
|
+
name: options.name,
|
|
138
|
+
scanned,
|
|
139
|
+
handled,
|
|
140
|
+
});
|
|
141
|
+
cursor = page.cursor;
|
|
142
|
+
if (cursor === undefined)
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
return { acquired: true, pages, scanned, handled };
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
if (await options.leases.release({
|
|
149
|
+
name: options.name,
|
|
150
|
+
owner: options.owner,
|
|
151
|
+
token: lease.token,
|
|
152
|
+
})) {
|
|
153
|
+
options.observe?.({ type: "released", name: options.name });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export class MemoryReconciliationLeaseStore {
|
|
158
|
+
durability = "memory";
|
|
159
|
+
records = new Map();
|
|
160
|
+
acquire(input) {
|
|
161
|
+
assertToken(input.name, "reconciliation lease name");
|
|
162
|
+
assertToken(input.owner, "reconciliation lease owner");
|
|
163
|
+
const current = this.records.get(input.name);
|
|
164
|
+
if (current?.owner !== undefined &&
|
|
165
|
+
current.expiresAt !== undefined &&
|
|
166
|
+
current.expiresAt > input.now) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
const token = crypto.randomUUID();
|
|
170
|
+
const expiresAt = input.now + input.leaseMs;
|
|
171
|
+
if (!Number.isSafeInteger(expiresAt))
|
|
172
|
+
throw new RangeError("reconciliation lease overflow");
|
|
173
|
+
this.records.set(input.name, {
|
|
174
|
+
owner: input.owner,
|
|
175
|
+
token,
|
|
176
|
+
expiresAt,
|
|
177
|
+
...(current?.cursor === undefined ? {} : { cursor: current.cursor }),
|
|
178
|
+
});
|
|
179
|
+
return Object.freeze({
|
|
180
|
+
name: input.name,
|
|
181
|
+
owner: input.owner,
|
|
182
|
+
token,
|
|
183
|
+
expiresAt,
|
|
184
|
+
...(current?.cursor === undefined ? {} : { cursor: current.cursor }),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
renew(input) {
|
|
188
|
+
const record = this.records.get(input.name);
|
|
189
|
+
if (record?.owner !== input.owner ||
|
|
190
|
+
!safeEqual(record.token, input.token) ||
|
|
191
|
+
(record.expiresAt ?? 0) <= input.now)
|
|
192
|
+
return false;
|
|
193
|
+
const expiresAt = input.now + input.leaseMs;
|
|
194
|
+
if (!Number.isSafeInteger(expiresAt))
|
|
195
|
+
throw new RangeError("reconciliation lease overflow");
|
|
196
|
+
record.expiresAt = expiresAt;
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
checkpoint(input) {
|
|
200
|
+
const record = this.records.get(input.name);
|
|
201
|
+
if (record?.owner !== input.owner || !safeEqual(record.token, input.token))
|
|
202
|
+
return false;
|
|
203
|
+
if (input.cursor === undefined)
|
|
204
|
+
delete record.cursor;
|
|
205
|
+
else
|
|
206
|
+
record.cursor = input.cursor;
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
release(input) {
|
|
210
|
+
const record = this.records.get(input.name);
|
|
211
|
+
if (record?.owner !== input.owner || !safeEqual(record.token, input.token))
|
|
212
|
+
return false;
|
|
213
|
+
delete record.owner;
|
|
214
|
+
delete record.token;
|
|
215
|
+
delete record.expiresAt;
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export function runEffectReconciliationWorker(store, options) {
|
|
220
|
+
return runReconciliationWorker({
|
|
221
|
+
...options,
|
|
222
|
+
scan: ({ cursor, limit }) => reconcileEffectsPage(store, {
|
|
223
|
+
staleBefore: options.staleBefore,
|
|
224
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
225
|
+
limit,
|
|
226
|
+
}),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
export function runSagaReconciliationWorker(store, options) {
|
|
230
|
+
return runReconciliationWorker({
|
|
231
|
+
...options,
|
|
232
|
+
scan: ({ cursor, limit }) => reconcileSagasPage(store, {
|
|
233
|
+
staleBefore: options.staleBefore,
|
|
234
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
235
|
+
limit,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=reconciliation-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciliation-worker.js","sourceRoot":"","sources":["../src/reconciliation-worker.ts"],"names":[],"mappings":"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"}
|
package/dist/router/pattern.d.ts
CHANGED
|
@@ -8,6 +8,19 @@ export type RoutePatternSegment = {
|
|
|
8
8
|
} | {
|
|
9
9
|
readonly kind: "wildcard";
|
|
10
10
|
readonly name: string;
|
|
11
|
+
}
|
|
12
|
+
/** A segment that is part literal, part parameter: `:key.txt`, `feed.:format`, `v:major.:minor`. */
|
|
13
|
+
| {
|
|
14
|
+
readonly kind: "mixed";
|
|
15
|
+
readonly parts: readonly MixedPart[];
|
|
16
|
+
};
|
|
17
|
+
/** One piece of a {@link RoutePatternSegment} of kind `mixed`, in left-to-right order. */
|
|
18
|
+
export type MixedPart = {
|
|
19
|
+
readonly t: "lit";
|
|
20
|
+
readonly v: string;
|
|
21
|
+
} | {
|
|
22
|
+
readonly t: "param";
|
|
23
|
+
readonly name: string;
|
|
11
24
|
};
|
|
12
25
|
/**
|
|
13
26
|
* Compiled route grammar shared by runtime routers, browser navigation, mocks, and adapters.
|
|
@@ -29,9 +42,21 @@ export type RoutePatternMatch = {
|
|
|
29
42
|
readonly matched: false;
|
|
30
43
|
readonly reason: "not-found" | "malformed";
|
|
31
44
|
};
|
|
45
|
+
/** The regex source matching one segment's worth of a mixed pattern, with a capture per parameter. */
|
|
46
|
+
export declare function mixedSegmentSource(parts: readonly MixedPart[]): string;
|
|
32
47
|
/** Parse and validate Nifra's strict route grammar once. Trailing slashes remain significant. */
|
|
33
48
|
export declare function compileRoutePattern(pattern: string): CompiledRoutePattern;
|
|
34
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Total ordering for mixed segment shapes, shared by the trie and regex-based routers.
|
|
51
|
+
*
|
|
52
|
+
* Code-unit comparison, never `localeCompare`: this exists so the server and the browser agree on which
|
|
53
|
+
* of two equally-weighted patterns wins, and `localeCompare` answers by the RUNTIME's locale - a server
|
|
54
|
+
* and a visitor in different locales would order the same pair differently, which is the divergence
|
|
55
|
+
* being prevented.
|
|
56
|
+
*/
|
|
57
|
+
export declare function compareMixedPartsSpecificity(left: readonly MixedPart[], right: readonly MixedPart[]): number;
|
|
58
|
+
/** Core precedence: static > mixed > param > wildcard at the first differing segment, independent of
|
|
59
|
+
* registration order. */
|
|
35
60
|
export declare function compareRoutePatternSpecificity(left: CompiledRoutePattern, right: CompiledRoutePattern): number;
|
|
36
61
|
/** Decode router captures under one rule. Plain values take the zero-allocation path; malformed
|
|
37
62
|
* escapes return `null`, allowing HTTP to emit 400 while client navigation declines the match. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../src/router/pattern.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,sBAAsB,EAAE,OAAO,MAA+C,CAAA;AAEpF,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../src/router/pattern.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,sBAAsB,EAAE,OAAO,MAA+C,CAAA;AAEpF,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACtD,oGAAoG;GAClG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,CAAA;AAEpE,0FAA0F;AAC1F,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAElD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,CAAC,sBAAsB,CAAC,EAAE,IAAI,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAA;IACjD,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CACvC;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACnE;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAA;CAAE,CAAA;AA4G3E,sGAAsG;AACtG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAUtE;AAED,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,CA4FzE;AAWD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,KAAK,EAAE,SAAS,SAAS,EAAE,GAC1B,MAAM,CAoBR;AAED;yBACyB;AACzB,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,oBAAoB,GAC1B,MAAM,CAeR;AAED;kGACkG;AAClG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAa5F;AAED,sGAAsG;AACtG,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,oBAAoB,EAC9B,QAAQ,EAAE,MAAM,GACf,iBAAiB,CAWnB"}
|
package/dist/router/pattern.js
CHANGED
|
@@ -18,7 +18,9 @@ function regexOf(compiled) {
|
|
|
18
18
|
? escapeRegex(segment.value)
|
|
19
19
|
: segment.kind === "param"
|
|
20
20
|
? "([^/]+)"
|
|
21
|
-
: "
|
|
21
|
+
: segment.kind === "mixed"
|
|
22
|
+
? mixedSegmentSource(segment.parts)
|
|
23
|
+
: "(.+)");
|
|
22
24
|
regex = new RegExp(parts.length === 0 ? "^/$" : `^/${parts.join("/")}$`);
|
|
23
25
|
REGEX_CACHE.set(compiled, regex);
|
|
24
26
|
}
|
|
@@ -27,9 +29,93 @@ function regexOf(compiled) {
|
|
|
27
29
|
function validParamName(name) {
|
|
28
30
|
return PARAM_NAME.test(name) && !RESERVED_PARAM_NAMES.has(name);
|
|
29
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Explain WHY a parameter name was rejected, in the terms the author was thinking in.
|
|
34
|
+
*
|
|
35
|
+
* The grammar is per-segment: a segment is wholly static or wholly a parameter, so everything after
|
|
36
|
+
* the colon is the name. `/v/:id.json` therefore asks for a parameter literally named `id.json`,
|
|
37
|
+
* which is not what anyone means by it — but the bare "invalid parameter" that produces reads as a
|
|
38
|
+
* typo rather than as a rule, leaving the author to guess whether the dot, the length, or the casing
|
|
39
|
+
* was the problem. Naming the actual limitation and showing the two ways out is the difference
|
|
40
|
+
* between a five-second fix and a trip to the source.
|
|
41
|
+
*/
|
|
42
|
+
function paramNameHint(name) {
|
|
43
|
+
if (RESERVED_PARAM_NAMES.has(name))
|
|
44
|
+
return ` — "${name}" is reserved (prototype key)`;
|
|
45
|
+
if (name.length === 0)
|
|
46
|
+
return ` — ":" needs a name after it`;
|
|
47
|
+
// No "a segment is wholly static or wholly a parameter" case here any more: mixed segments made
|
|
48
|
+
// that message obsolete. `:id.json` was the shape it explained, and `:id.json` now compiles.
|
|
49
|
+
return ` — a name must match ${PARAM_NAME.source}`;
|
|
50
|
+
}
|
|
30
51
|
function escapeRegex(value) {
|
|
31
52
|
return value.replace(/[.*+?^()|[\]\\{}$]/g, "\\$&");
|
|
32
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Split a segment containing `:` into literal and parameter parts.
|
|
56
|
+
*
|
|
57
|
+
* The param name is the LONGEST run matching {@link PARAM_NAME}'s body after each `:`; everything
|
|
58
|
+
* else in the segment is literal. So `:key.txt` is `[param key][lit ".txt"]`. Choosing a greedy scan
|
|
59
|
+
* on the existing sigil rather than a new `{key}.txt` syntax is a safety argument, not a taste one:
|
|
60
|
+
* every segment this newly accepts currently THROWS `INVALID_PARAM_NAME`, so no pattern that compiles
|
|
61
|
+
* today can change meaning.
|
|
62
|
+
*
|
|
63
|
+
* Returns `undefined` when the segment holds no parameter at all, so a literal colon
|
|
64
|
+
* (`/v1/things:batchGet` - legal in a URL path) stays a plain static segment.
|
|
65
|
+
*/
|
|
66
|
+
function splitMixed(value) {
|
|
67
|
+
const parts = [];
|
|
68
|
+
let literal = "";
|
|
69
|
+
let sawParam = false;
|
|
70
|
+
for (let i = 0; i < value.length; i++) {
|
|
71
|
+
if (value[i] !== ":") {
|
|
72
|
+
literal += value[i];
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const rest = value.slice(i + 1);
|
|
76
|
+
const name = /^[A-Za-z_][A-Za-z0-9_]*/.exec(rest)?.[0];
|
|
77
|
+
// A `:` not followed by a valid name start is literal text, not a malformed parameter.
|
|
78
|
+
if (name === undefined) {
|
|
79
|
+
literal += ":";
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const paramEnd = i + 1 + name.length;
|
|
83
|
+
const previous = i > 0 ? value[i - 1] : undefined;
|
|
84
|
+
const precededByBoundary = previous === undefined || !/[A-Za-z0-9_]/.test(previous);
|
|
85
|
+
// Preserve established RPC-style literals such as `things:batchGet`. A colon embedded after an
|
|
86
|
+
// identifier and running to the end is literal; mixed params remain unambiguous at segment start,
|
|
87
|
+
// after punctuation (`post-:id`), or when followed by a literal suffix (`v:major.json`).
|
|
88
|
+
if (!precededByBoundary && paramEnd === value.length) {
|
|
89
|
+
literal += `:${name}`;
|
|
90
|
+
i += name.length;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (literal !== "") {
|
|
94
|
+
parts.push({ t: "lit", v: literal });
|
|
95
|
+
literal = "";
|
|
96
|
+
}
|
|
97
|
+
parts.push({ t: "param", name });
|
|
98
|
+
sawParam = true;
|
|
99
|
+
i += name.length;
|
|
100
|
+
}
|
|
101
|
+
if (!sawParam)
|
|
102
|
+
return undefined;
|
|
103
|
+
if (literal !== "")
|
|
104
|
+
parts.push({ t: "lit", v: literal });
|
|
105
|
+
return parts;
|
|
106
|
+
}
|
|
107
|
+
/** The regex source matching one segment's worth of a mixed pattern, with a capture per parameter. */
|
|
108
|
+
export function mixedSegmentSource(parts) {
|
|
109
|
+
let source = "";
|
|
110
|
+
for (const part of parts) {
|
|
111
|
+
// LAZY (`+?`), not greedy. A greedy capture swallows the trailing literal, so `/:key.txt` against
|
|
112
|
+
// `/abc.txt` would capture `abc.txt` and then fail to match `\.txt`. With `^…$` anchoring, the
|
|
113
|
+
// lazy form still yields `abc.txt` for `/abc.txt.txt` - the anchor forces the LAST `.txt` to be
|
|
114
|
+
// the literal. `+?` and not `*?`: an empty capture must not match (see the empty-segment rule).
|
|
115
|
+
source += part.t === "lit" ? escapeRegex(part.v) : "([^/]+?)";
|
|
116
|
+
}
|
|
117
|
+
return source;
|
|
118
|
+
}
|
|
33
119
|
/** Parse and validate Nifra's strict route grammar once. Trailing slashes remain significant. */
|
|
34
120
|
export function compileRoutePattern(pattern) {
|
|
35
121
|
if (pattern.length === 0 || pattern.charCodeAt(0) !== 47 /* / */) {
|
|
@@ -40,11 +126,18 @@ export function compileRoutePattern(pattern) {
|
|
|
40
126
|
const paramNames = [];
|
|
41
127
|
for (let i = 0; i < raw.length; i++) {
|
|
42
128
|
const value = raw[i];
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
129
|
+
// A leading `:` whose name run spans the WHOLE segment is a plain parameter - the untouched fast
|
|
130
|
+
// path. When it does not (`:key.txt`), the segment is mixed and is handled below; but a leading
|
|
131
|
+
// `:` that yields no usable name at all (`:9lives`, `:`) was clearly meant as a parameter, so it
|
|
132
|
+
// still fails here rather than being silently reinterpreted as literal text.
|
|
133
|
+
if (value.charCodeAt(0) === 58 /* : */ && !validParamName(value.slice(1))) {
|
|
134
|
+
if (splitMixed(value) === undefined) {
|
|
135
|
+
const name = value.slice(1);
|
|
136
|
+
throw new RouteConfigError("INVALID_PARAM_NAME", `invalid parameter ":${name}" in "${pattern}"${paramNameHint(name)}`);
|
|
47
137
|
}
|
|
138
|
+
}
|
|
139
|
+
else if (value.charCodeAt(0) === 58 /* : */) {
|
|
140
|
+
const name = value.slice(1);
|
|
48
141
|
if (paramNames.includes(name)) {
|
|
49
142
|
throw new RouteConfigError("DUPLICATE_PARAM", `duplicate parameter ":${name}" in "${pattern}"`);
|
|
50
143
|
}
|
|
@@ -67,6 +160,27 @@ export function compileRoutePattern(pattern) {
|
|
|
67
160
|
segments.push(Object.freeze({ kind: "wildcard", name }));
|
|
68
161
|
continue;
|
|
69
162
|
}
|
|
163
|
+
// A segment holding a `:` anywhere other than the front is part literal, part parameter. Checked
|
|
164
|
+
// last so the wholly-static and wholly-param fast paths above are untouched.
|
|
165
|
+
const mixed = value.includes(":") ? splitMixed(value) : undefined;
|
|
166
|
+
if (mixed !== undefined) {
|
|
167
|
+
for (const part of mixed) {
|
|
168
|
+
if (part.t !== "param")
|
|
169
|
+
continue;
|
|
170
|
+
if (!validParamName(part.name)) {
|
|
171
|
+
throw new RouteConfigError("INVALID_PARAM_NAME", `invalid parameter ":${part.name}" in "${pattern}"${paramNameHint(part.name)}`);
|
|
172
|
+
}
|
|
173
|
+
// Duplicates must be rejected WITHIN a segment (`/:a.:a`) as well as across segments,
|
|
174
|
+
// or two captures would race for one params key.
|
|
175
|
+
if (paramNames.includes(part.name)) {
|
|
176
|
+
throw new RouteConfigError("DUPLICATE_PARAM", `duplicate parameter ":${part.name}" in "${pattern}"`);
|
|
177
|
+
}
|
|
178
|
+
// Pushed left-to-right so `paramNames` stays aligned with regex capture order.
|
|
179
|
+
paramNames.push(part.name);
|
|
180
|
+
}
|
|
181
|
+
segments.push(Object.freeze({ kind: "mixed", parts: Object.freeze(mixed) }));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
70
184
|
segments.push(Object.freeze({ kind: "static", value }));
|
|
71
185
|
}
|
|
72
186
|
const compiled = Object.freeze({
|
|
@@ -77,7 +191,44 @@ export function compileRoutePattern(pattern) {
|
|
|
77
191
|
});
|
|
78
192
|
return compiled;
|
|
79
193
|
}
|
|
80
|
-
/**
|
|
194
|
+
/** Weight for {@link compareRoutePatternSpecificity}. A mixed segment constrains more than a bare
|
|
195
|
+
* param (it pins literal text) and less than a fully static one, so it sits between them. */
|
|
196
|
+
const SPECIFICITY = {
|
|
197
|
+
static: 4,
|
|
198
|
+
mixed: 3,
|
|
199
|
+
param: 2,
|
|
200
|
+
wildcard: 1,
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Total ordering for mixed segment shapes, shared by the trie and regex-based routers.
|
|
204
|
+
*
|
|
205
|
+
* Code-unit comparison, never `localeCompare`: this exists so the server and the browser agree on which
|
|
206
|
+
* of two equally-weighted patterns wins, and `localeCompare` answers by the RUNTIME's locale - a server
|
|
207
|
+
* and a visitor in different locales would order the same pair differently, which is the divergence
|
|
208
|
+
* being prevented.
|
|
209
|
+
*/
|
|
210
|
+
export function compareMixedPartsSpecificity(left, right) {
|
|
211
|
+
const literalWeight = (parts) => parts.reduce((sum, part) => (part.t === "lit" ? sum + part.v.length : sum), 0);
|
|
212
|
+
const order = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
213
|
+
const weightDifference = literalWeight(right) - literalWeight(left);
|
|
214
|
+
if (weightDifference !== 0)
|
|
215
|
+
return weightDifference;
|
|
216
|
+
const length = Math.max(left.length, right.length);
|
|
217
|
+
for (let i = 0; i < length; i++) {
|
|
218
|
+
const a = left[i];
|
|
219
|
+
const b = right[i];
|
|
220
|
+
if (a === undefined || b === undefined)
|
|
221
|
+
return b === undefined ? -1 : 1;
|
|
222
|
+
if (a.t !== b.t)
|
|
223
|
+
return a.t === "lit" ? -1 : 1;
|
|
224
|
+
if (a.t === "lit" && b.t === "lit" && a.v !== b.v) {
|
|
225
|
+
return a.v.length === b.v.length ? order(a.v, b.v) : b.v.length - a.v.length;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return order(mixedSegmentSource(left), mixedSegmentSource(right));
|
|
229
|
+
}
|
|
230
|
+
/** Core precedence: static > mixed > param > wildcard at the first differing segment, independent of
|
|
231
|
+
* registration order. */
|
|
81
232
|
export function compareRoutePatternSpecificity(left, right) {
|
|
82
233
|
const length = Math.max(left.segments.length, right.segments.length);
|
|
83
234
|
for (let i = 0; i < length; i++) {
|
|
@@ -85,10 +236,15 @@ export function compareRoutePatternSpecificity(left, right) {
|
|
|
85
236
|
const b = right.segments[i];
|
|
86
237
|
if (a === undefined || b === undefined)
|
|
87
238
|
return b === undefined ? -1 : 1;
|
|
88
|
-
const aWeight = a.kind
|
|
89
|
-
const bWeight = b.kind
|
|
239
|
+
const aWeight = SPECIFICITY[a.kind];
|
|
240
|
+
const bWeight = SPECIFICITY[b.kind];
|
|
90
241
|
if (aWeight !== bWeight)
|
|
91
242
|
return bWeight - aWeight;
|
|
243
|
+
if (a.kind === "mixed" && b.kind === "mixed") {
|
|
244
|
+
const mixed = compareMixedPartsSpecificity(a.parts, b.parts);
|
|
245
|
+
if (mixed !== 0)
|
|
246
|
+
return mixed;
|
|
247
|
+
}
|
|
92
248
|
}
|
|
93
249
|
return 0;
|
|
94
250
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pattern.js","sourceRoot":"","sources":["../../src/router/pattern.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,UAAU,GAAG,0BAA0B,CAAA;AAC7C,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAA;AAC/E,MAAM,sBAAsB,GAAkB,MAAM,CAAC,8BAA8B,CAAC,CAAA;AAyBpF;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAI,OAAO,EAAgC,CAAA;AAE/D,SAAS,OAAO,CAAC,QAA8B;IAC7C,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,QAAQ,CAAC,sBAAsB,CAAC,KAAK,IAAI,EAAE,CAAC;YAC9C,MAAM,IAAI,SAAS,CAAC,yDAAyD,CAAC,CAAA;QAChF,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAC9C,OAAO,CAAC,IAAI,KAAK,QAAQ;YACvB,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;YAC5B,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO;gBACxB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,MAAM,CACb,CAAA;QACD,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACxE,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC;QACjE,MAAM,IAAI,gBAAgB,CAAC,cAAc,EAAE,8BAA8B,OAAO,GAAG,CAAC,CAAA;IACtF,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC9D,MAAM,QAAQ,GAA0B,EAAE,CAAA;IAC1C,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAE,CAAA;QACrB,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC3B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,gBAAgB,CACxB,oBAAoB,EACpB,uBAAuB,IAAI,SAAS,OAAO,GAAG,CAC/C,CAAA;YACH,CAAC;YACD,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,gBAAgB,CACxB,iBAAiB,EACjB,yBAAyB,IAAI,SAAS,OAAO,GAAG,CACjD,CAAA;YACH,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YACrD,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,gBAAgB,CACxB,mBAAmB,EACnB,0CAA0C,OAAO,GAAG,CACrD,CAAA;YACH,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACtD,IAAI,IAAI,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,gBAAgB,CACxB,oBAAoB,EACpB,sBAAsB,IAAI,SAAS,OAAO,GAAG,CAC9C,CAAA;YACH,CAAC;YACD,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,gBAAgB,CACxB,iBAAiB,EACjB,wBAAwB,IAAI,SAAS,OAAO,GAAG,CAChD,CAAA;YACH,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YACxD,SAAQ;QACV,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IACzD,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7B,CAAC,sBAAsB,CAAC,EAAE,IAAI;QAC9B,OAAO;QACP,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;QACjC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;KACtC,CAAyB,CAAA;IAC1B,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,8BAA8B,CAC5C,IAA0B,EAC1B,KAA2B;IAE3B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QAC3B,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACvE,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACpE,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACpE,IAAI,OAAO,KAAK,OAAO;YAAE,OAAO,OAAO,GAAG,OAAO,CAAA;IACnD,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED;kGACkG;AAClG,MAAM,UAAU,iBAAiB,CAAC,GAA2B;IAC3D,IAAI,GAAuC,CAAA;IAC3C,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAE,CAAA;QACvB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAQ;QAClC,IAAI,CAAC;YACH,GAAG,KAAK,EAAE,GAAG,GAAG,EAAE,CAAA;YAClB,GAAG,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,IAAI,GAAG,CAAA;AACnB,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,iBAAiB,CAC/B,QAA8B,EAC9B,QAAgB;IAEhB,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;IAClE,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IACtD,CAAC;IACD,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;IACzC,OAAO,OAAO,KAAK,IAAI;QACrB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE;QACzC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AACxC,CAAC"}
|
|
1
|
+
{"version":3,"file":"pattern.js","sourceRoot":"","sources":["../../src/router/pattern.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,oBAAoB,EAK1B,MAAM,cAAc,CAAA;AAErB,uCAAuC;AACvC,eAAO,MAAM,OAAO,uEAAwE,CAAA;AAE5F,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;AAS7C,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAqB,CAAA;AAGrE;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IACrB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACtF;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AA0NhG;;;;;;;;GAQG;AACH,qBAAa,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;IACvD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;;IAQ7C;;;;OAIG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,oBAAoB,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IAqF7E;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC;IAelD,OAAO,CAAC,WAAW;IA8BnB,OAAO,CAAC,sBAAsB;CAwB/B"}
|
package/dist/router/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RouteConfigError } from "../errors.js";
|
|
2
|
-
import { compileRoutePattern } from "./pattern.js";
|
|
2
|
+
import { compareMixedPartsSpecificity, compileRoutePattern, mixedSegmentSource, } from "./pattern.js";
|
|
3
3
|
/** HTTP methods the router accepts. */
|
|
4
4
|
export const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
5
5
|
const METHOD_SET = new Set(METHODS);
|
|
@@ -26,6 +26,7 @@ function createNode() {
|
|
|
26
26
|
return {
|
|
27
27
|
staticChildren: new Map(),
|
|
28
28
|
paramChild: undefined,
|
|
29
|
+
mixedChildren: undefined,
|
|
29
30
|
wildcardChild: undefined,
|
|
30
31
|
terminal: undefined,
|
|
31
32
|
};
|
|
@@ -66,6 +67,33 @@ function matchNode(node, path, start, len, paramValues) {
|
|
|
66
67
|
return found;
|
|
67
68
|
}
|
|
68
69
|
}
|
|
70
|
+
// Mixed sits between static and param: it pins literal text, so it is more specific than a bare
|
|
71
|
+
// `:param`, and less than an exact segment. Guarded on `undefined` so a mixed-free route table
|
|
72
|
+
// never enters this branch.
|
|
73
|
+
const mixedChildren = node.mixedChildren;
|
|
74
|
+
if (mixedChildren !== undefined && seg.length > 0) {
|
|
75
|
+
for (const child of mixedChildren) {
|
|
76
|
+
const matched = child.regex.exec(seg);
|
|
77
|
+
if (matched === null)
|
|
78
|
+
continue;
|
|
79
|
+
// Push left-to-right, matching the order `paramNames` was built in.
|
|
80
|
+
for (let i = 1; i <= child.arity; i++)
|
|
81
|
+
paramValues.push(matched[i]);
|
|
82
|
+
if (isLast) {
|
|
83
|
+
if (child.node.terminal !== undefined)
|
|
84
|
+
return child.node.terminal;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const found = matchNode(child.node, path, end + 1, len, paramValues);
|
|
88
|
+
if (found !== undefined)
|
|
89
|
+
return found;
|
|
90
|
+
}
|
|
91
|
+
// Backtrack: a mixed segment pushed `arity` values, not one, so unwind exactly that many or
|
|
92
|
+
// every later param reads a value belonging to an abandoned branch.
|
|
93
|
+
for (let i = 0; i < child.arity; i++)
|
|
94
|
+
paramValues.pop();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
69
97
|
const paramChild = node.paramChild;
|
|
70
98
|
// An empty segment (`/users//posts`) never matches a `:param` — matching would hand the handler
|
|
71
99
|
// `id: ""` and downstream code a `WHERE id = ''` class of bug. Peers (Hono, Elysia, Next) 404
|
|
@@ -183,6 +211,26 @@ export class Router {
|
|
|
183
211
|
node.wildcardChild ??= createNode();
|
|
184
212
|
node = node.wildcardChild;
|
|
185
213
|
}
|
|
214
|
+
else if (segment.kind === "mixed") {
|
|
215
|
+
const source = mixedSegmentSource(segment.parts);
|
|
216
|
+
node.mixedChildren ??= [];
|
|
217
|
+
let child = node.mixedChildren.find((entry) => entry.source === source);
|
|
218
|
+
if (child === undefined) {
|
|
219
|
+
child = {
|
|
220
|
+
regex: new RegExp(`^${source}$`),
|
|
221
|
+
arity: segment.parts.reduce((n, part) => (part.t === "param" ? n + 1 : n), 0),
|
|
222
|
+
parts: segment.parts,
|
|
223
|
+
node: createNode(),
|
|
224
|
+
source,
|
|
225
|
+
};
|
|
226
|
+
node.mixedChildren.push(child);
|
|
227
|
+
// Most literal text first. Registration order must not decide which of `/:id.txt` and
|
|
228
|
+
// `/:id.json` wins, and re-sorting on insert (a boot-time cost) keeps the match path a
|
|
229
|
+
// straight scan.
|
|
230
|
+
node.mixedChildren.sort((a, b) => compareMixedPartsSpecificity(a.parts, b.parts));
|
|
231
|
+
}
|
|
232
|
+
node = child.node;
|
|
233
|
+
}
|
|
186
234
|
else {
|
|
187
235
|
let child = node.staticChildren.get(segment.value);
|
|
188
236
|
if (child === undefined) {
|