@gusnips/react 0.9.23 → 0.9.25
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 +36 -36
- package/dist/api-client.d.ts +51 -51
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +3 -3
- package/dist/api-error.d.ts +11 -11
- package/dist/api-error.js +11 -11
- package/dist/auth-email.d.ts +40 -0
- package/dist/auth-email.d.ts.map +1 -0
- package/dist/auth-email.js +106 -0
- package/dist/auth-email.js.map +1 -0
- package/dist/auth-store.d.ts +23 -23
- package/dist/auth-store.js +13 -13
- package/dist/copy.d.ts +3 -3
- package/dist/copy.js +3 -3
- package/dist/deploy-recovery.d.ts +40 -40
- package/dist/deploy-recovery.js +40 -40
- package/dist/describe-error.d.ts +68 -68
- package/dist/describe-error.d.ts.map +1 -1
- package/dist/describe-error.js +5 -5
- package/dist/error-boundary.d.ts +12 -12
- package/dist/guards.d.ts +15 -15
- package/dist/guards.js +3 -3
- package/dist/hydrate.d.ts +15 -16
- package/dist/hydrate.d.ts.map +1 -1
- package/dist/hydrate.js +9 -9
- package/dist/hydrate.js.map +1 -1
- package/dist/i18n.d.ts +15 -16
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +5 -6
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal-path.d.ts +8 -7
- package/dist/internal-path.d.ts.map +1 -1
- package/dist/internal-path.js +12 -9
- package/dist/internal-path.js.map +1 -1
- package/dist/prerender-contract.d.ts +7 -7
- package/dist/prerender-contract.js +7 -7
- package/dist/query.d.ts +16 -17
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +2 -2
- package/dist/query.js.map +1 -1
- package/dist/sse.d.ts +19 -20
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +18 -19
- package/dist/sse.js.map +1 -1
- package/dist/states.d.ts +12 -12
- package/dist/states.d.ts.map +1 -1
- package/dist/supabase-session.d.ts +47 -48
- package/dist/supabase-session.d.ts.map +1 -1
- package/dist/supabase-session.js +35 -35
- package/dist/supabase-session.js.map +1 -1
- package/dist/theme.d.ts +4 -4
- package/dist/theme.js +4 -4
- package/dist/ui/class-name.d.ts +3 -4
- package/dist/ui/class-name.d.ts.map +1 -1
- package/dist/ui/class-name.js +3 -4
- package/dist/ui/class-name.js.map +1 -1
- package/dist/ui/combobox.d.ts +11 -11
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/dialog.d.ts +5 -5
- package/dist/ui/dialog.js +2 -2
- package/dist/ui/drawer.d.ts +10 -10
- package/dist/ui/drawer.d.ts.map +1 -1
- package/dist/ui/drawer.js +2 -2
- package/dist/ui/input.d.ts +2 -2
- package/dist/ui/input.js +2 -2
- package/dist/ui/menu.d.ts +8 -8
- package/dist/ui/menu.d.ts.map +1 -1
- package/dist/ui/menu.js +4 -4
- package/dist/ui/menu.js.map +1 -1
- package/dist/ui/select.d.ts +12 -12
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +3 -3
- package/dist/ui/tabs.d.ts +14 -15
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +13 -14
- package/dist/ui/tabs.js.map +1 -1
- package/package.json +1 -1
- package/src/api-client.ts +51 -51
- package/src/api-error.ts +11 -11
- package/src/auth-email.test.ts +145 -0
- package/src/auth-email.ts +112 -0
- package/src/auth-store.ts +23 -23
- package/src/copy.ts +3 -3
- package/src/deploy-recovery.ts +40 -40
- package/src/describe-error.ts +68 -68
- package/src/error-boundary.tsx +12 -12
- package/src/guards.tsx +15 -15
- package/src/hydrate.ts +15 -16
- package/src/i18n.ts +15 -16
- package/src/index.ts +2 -0
- package/src/internal-path.test.ts +1 -0
- package/src/internal-path.ts +12 -9
- package/src/prerender-contract.ts +7 -7
- package/src/query.ts +16 -17
- package/src/sse.ts +19 -20
- package/src/states.ts +12 -12
- package/src/supabase-session.ts +46 -47
- package/src/theme.ts +4 -4
- package/src/ui/class-name.ts +3 -4
- package/src/ui/combobox.tsx +11 -11
- package/src/ui/dialog.tsx +5 -5
- package/src/ui/drawer.tsx +10 -10
- package/src/ui/input.tsx +2 -2
- package/src/ui/menu.tsx +8 -8
- package/src/ui/select.tsx +12 -12
- package/src/ui/tabs.tsx +14 -15
package/dist/describe-error.d.ts
CHANGED
|
@@ -3,21 +3,21 @@ import { ApiError } from "./api-error.ts";
|
|
|
3
3
|
* Turning anything thrown into copy a person can act on.
|
|
4
4
|
*
|
|
5
5
|
* The API already answers with a message written for a developer, a stable `messageKey` for the
|
|
6
|
-
* domain refusals, and `details` carrying the parts that make a refusal actionable. This is the
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* domain refusals, and `details` carrying the parts that make a refusal actionable. This is the one
|
|
7
|
+
* place that decides what the SCREEN says. It is not always the same sentence. "Monthly quota
|
|
8
|
+
* spent, upgrade or buy a pack" is right in a JSON body and wrong under a button that could just
|
|
9
|
+
* say what to do next.
|
|
10
10
|
*
|
|
11
11
|
* `cause` is what happened. `fix` is what to do about it. **A surface that shows only the first
|
|
12
|
-
* half is the dead end this exists to prevent
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* half is the dead end this exists to prevent**. That is why the type has two fields and not one,
|
|
13
|
+
* and why `fix` being absent should be a deliberate choice at each call site rather than the
|
|
14
|
+
* default nobody noticed.
|
|
15
15
|
*
|
|
16
|
-
* `fix`, and not the `hint` this returned until 0.6.0. `ErrorStateProps
|
|
17
|
-
* package ships for the component that renders this
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* `fix`, and not the `hint` this returned until 0.6.0. `ErrorStateProps`, the contract this same
|
|
17
|
+
* package ships for the component that renders this, has always called it `fix`, so every adopter
|
|
18
|
+
* wrote `fix={hint}` at every error surface: a rename adapter, which is the shape of an API we got
|
|
19
|
+
* wrong. It also clears a collision, because in at least one adopter a form field's `hint` is the
|
|
20
|
+
* requirement text under the input, which is a different thing entirely.
|
|
21
21
|
*
|
|
22
22
|
* The per-code switch stays in the product: two donors' switches shared their SHAPE and almost
|
|
23
23
|
* no arms, because the arms are that API's vocabulary. What ships is the scaffolding around it,
|
|
@@ -26,11 +26,11 @@ import { ApiError } from "./api-error.ts";
|
|
|
26
26
|
/**
|
|
27
27
|
* Which control to offer beside the words.
|
|
28
28
|
*
|
|
29
|
-
* The fourth adopter had this and the package did not, which left every adopter re-deriving
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
29
|
+
* The fourth adopter had this and the package did not, which left every adopter re-deriving "can a
|
|
30
|
+
* second attempt fix this" from its own switch, beside a `shouldRetry` already deciding exactly
|
|
31
|
+
* that for react-query. Two answers to one question drift, and the drift is visible: a screen
|
|
32
|
+
* offering "try again" for a refusal the query layer refuses to retry, so the button does nothing
|
|
33
|
+
* and the reader presses it twice.
|
|
34
34
|
*
|
|
35
35
|
* So this is DERIVED from `shouldRetry`, not switched on separately. One rule, two consumers.
|
|
36
36
|
*/
|
|
@@ -49,7 +49,7 @@ export interface ErrorCopy {
|
|
|
49
49
|
cause: string;
|
|
50
50
|
/** What to do about it. Its absence should be a decision, not an oversight. */
|
|
51
51
|
fix?: string;
|
|
52
|
-
/** Override the derived kind
|
|
52
|
+
/** Override the derived kind. A 429 whose code means a spent quota is `"none"`, not `"wait"`. */
|
|
53
53
|
recover?: RecoveryKind;
|
|
54
54
|
/** Override the request id. Rarely wanted; the envelope's is used by default. */
|
|
55
55
|
reference?: string;
|
|
@@ -59,14 +59,14 @@ export interface DescribedError extends ErrorCopy {
|
|
|
59
59
|
recover: RecoveryKind;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* The subset of i18next's `t` this module needs
|
|
62
|
+
* The subset of i18next's `t` this module needs, typed here so `i18next` stays optional.
|
|
63
63
|
*
|
|
64
|
-
* `Key` is a parameter and not plain `string` for a reason the first migration found. Every app
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
64
|
+
* `Key` is a parameter and not plain `string` for a reason the first migration found. Every app on
|
|
65
|
+
* this stack declares `CustomTypeOptions.resources`, which types `t` to accept ONLY the keys its
|
|
66
|
+
* catalog has, so a `t` is not assignable to anything asking for `(key: string) => string`, and the
|
|
67
|
+
* adopter is left with a cast. Naming the keys instead turns that around: each function below asks
|
|
68
|
+
* for exactly the keys it looks up, a typed `t` accepts a superset of them and goes in directly,
|
|
69
|
+
* and a catalog missing one is a compile error rather than a raw key on screen.
|
|
70
70
|
*/
|
|
71
71
|
export type Translate<Key extends string = string> = (key: Key, params?: Record<string, unknown>) => string;
|
|
72
72
|
/** The three names {@link humanizeWait} looks up, under whatever prefix you pass it. */
|
|
@@ -75,8 +75,8 @@ type WaitName = "waitSeconds" | "waitMinutes" | "waitHours";
|
|
|
75
75
|
* Every name {@link createErrorDescriber} looks up itself. Your catalog carries all of them.
|
|
76
76
|
*
|
|
77
77
|
* The three wait names are deliberately NOT here, which is the other half of 0.6.0. This module
|
|
78
|
-
* used to humanize a stated wait itself, so `waitSeconds`/`waitMinutes`/`waitHours
|
|
79
|
-
*
|
|
78
|
+
* used to humanize a stated wait itself, so `waitSeconds`/`waitMinutes`/`waitHours`, each with an
|
|
79
|
+
* ICU plural, landed in the key union of every adopter's `t` whether or not a wait was ever
|
|
80
80
|
* rendered. An app that formats waits with `Intl.RelativeTimeFormat` needs none of them and was
|
|
81
81
|
* left adding six entries per language to satisfy a compiler. `formatWait` owns that now.
|
|
82
82
|
*/
|
|
@@ -86,26 +86,26 @@ type CopyName = "network" | "networkHint" | "unexpected" | "retrySoon";
|
|
|
86
86
|
*
|
|
87
87
|
* i18next keeps `seatLimitReached_one` and `seatLimitReached_other`; the server sends
|
|
88
88
|
* `serverErrors.seatLimitReached`, because that is the key a person resolves with a `count`. So
|
|
89
|
-
* `Object.keys` on a catalog does NOT contain the name the server actually sends, and a gate
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
89
|
+
* `Object.keys` on a catalog does NOT contain the name the server actually sends, and a gate built
|
|
90
|
+
* from it alone rejects a sentence the app is carrying, falling back to the server's English for
|
|
91
|
+
* the one refusal that had a written answer. Measured in the seventh migration: two of that API's
|
|
92
|
+
* 112 keys, both of them plan limits, both of them the exact screen where a specific sentence earns
|
|
93
|
+
* its keep.
|
|
94
94
|
*/
|
|
95
95
|
type PluralSuffix = "zero" | "one" | "two" | "few" | "many" | "other";
|
|
96
96
|
type PluralBase<N extends string> = N extends `${infer Base}_${PluralSuffix}` ? Base : N;
|
|
97
97
|
/**
|
|
98
|
-
* "in 4 minutes"
|
|
98
|
+
* Format a wait as "in 4 minutes" or "in 2 hours", without making the reader convert seconds.
|
|
99
99
|
*
|
|
100
100
|
* The thresholds are deliberately not round: 90 seconds rather than 60, so "in 75 seconds" does
|
|
101
101
|
* not become the less precise "in 1 minute", and 90 minutes rather than 60 for the same reason
|
|
102
102
|
* one rung up. Needs `waitSeconds` / `waitMinutes` / `waitHours` under `prefix`, each with a
|
|
103
103
|
* `count` plural.
|
|
104
104
|
*
|
|
105
|
-
* This is what you pass as `formatWait` when your catalog carries those three:
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
105
|
+
* This is what you pass as `formatWait` when your catalog carries those three: `formatWait: (secs)
|
|
106
|
+
* => humanizeWait(t, secs, "errors.")`. An app that formats a wait with `Intl.RelativeTimeFormat`
|
|
107
|
+
* passes its own one-liner instead and needs no wait keys at all. It also gets correct plurals in
|
|
108
|
+
* languages with more than two forms, for free.
|
|
109
109
|
*/
|
|
110
110
|
export declare function humanizeWait<Prefix extends string>(t: Translate<`${Prefix}${WaitName}`>, secs: number, prefix: Prefix): string;
|
|
111
111
|
export interface ErrorContext {
|
|
@@ -129,17 +129,17 @@ interface DescriberRules {
|
|
|
129
129
|
* How a stated wait becomes words, for the `wait` an arm reads off its context.
|
|
130
130
|
*
|
|
131
131
|
* Required rather than defaulted, because there is no answer that is right for everyone and a
|
|
132
|
-
* default hid the cost: {@link humanizeWait} reads three ICU plural keys out of your catalog,
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
132
|
+
* default hid the cost: {@link humanizeWait} reads three ICU plural keys out of your catalog, and
|
|
133
|
+
* an app that already formats relative time with `Intl` would have had to add them to compile.
|
|
134
|
+
* Pass `(secs) => humanizeWait(t, secs, "errors.")` or your own `(secs) => formatIn(secs,
|
|
135
|
+
* locale)`. The choice makes the catalog you need visible.
|
|
136
136
|
*/
|
|
137
137
|
formatWait: (secs: number) => string;
|
|
138
138
|
/**
|
|
139
139
|
* Per-code copy. Everything not listed falls through to the default arm.
|
|
140
140
|
*
|
|
141
|
-
* The arms look up the app's own keys, so they close over the app's `t` rather than being
|
|
142
|
-
*
|
|
141
|
+
* The arms look up the app's own keys, so they close over the app's `t` rather than being handed
|
|
142
|
+
* one. This module has no names for that copy and no business typing it.
|
|
143
143
|
*
|
|
144
144
|
* Annotate your object `Partial<Record<YourErrorCode, ErrorArm>>` where you write it, and a
|
|
145
145
|
* code that does not exist is a compile error at the arm rather than a branch that never runs.
|
|
@@ -149,21 +149,21 @@ interface DescriberRules {
|
|
|
149
149
|
* What to say when nothing in `codes` matches: a code this build has no arm for, or an answer
|
|
150
150
|
* with no envelope at all.
|
|
151
151
|
*
|
|
152
|
-
* The built-in arm hands the reader the server's own `message`, and for one API in the fleet
|
|
153
|
-
*
|
|
152
|
+
* The built-in arm hands the reader the server's own `message`, and for one API in the fleet that
|
|
153
|
+
* is right, because its message IS the sentence a person should read. For another it is exactly
|
|
154
154
|
* wrong: that repo's own i18n rules say `message` is "the English fallback for logs", and it
|
|
155
155
|
* ships three languages, so the built-in would put developer English in front of a reader who
|
|
156
|
-
* does not speak it. One default cannot be right for both, and the one baked in here was
|
|
157
|
-
*
|
|
156
|
+
* does not speak it. One default cannot be right for both, and the one baked in here was simply
|
|
157
|
+
* the first adopter's convention, mistaken for a fact.
|
|
158
158
|
*
|
|
159
159
|
* An arm here is also handed the stated wait, which the built-in spends on nothing: a refusal
|
|
160
160
|
* with no arm of its own could state its expiry and have that go unsaid.
|
|
161
161
|
*/
|
|
162
162
|
fallback?: ErrorArm;
|
|
163
163
|
/**
|
|
164
|
-
* The codes that mean "this limit does not clear by waiting"
|
|
165
|
-
* `queryDefaults`**, because it answers the same question and a second copy is a second
|
|
166
|
-
*
|
|
164
|
+
* The codes that mean "this limit does not clear by waiting". Pass **the same list to
|
|
165
|
+
* `queryDefaults`**, because it answers the same question and a second copy is a second chance to
|
|
166
|
+
* disagree with the retry rule. Declare it once in the app and pass it twice.
|
|
167
167
|
*/
|
|
168
168
|
durableLimitCodes?: readonly string[];
|
|
169
169
|
/** Longest stated wait still worth a retry rather than a countdown. Matches `queryDefaults`. */
|
|
@@ -173,23 +173,23 @@ export interface ErrorDescriberOptions<Prefix extends string, ServerPrefix exten
|
|
|
173
173
|
/**
|
|
174
174
|
* Checked against the keys, never used to find them: the three type parameters come from
|
|
175
175
|
* `copyPrefix`, `messageKeyPrefix` and `knownMessageKeys`. With `t` as a source too, the call
|
|
176
|
-
* every adopter writes
|
|
176
|
+
* every adopter writes, an inline `(key, params) => i18n.t(key, params)` beside an inline arm,
|
|
177
177
|
* failed overload resolution (TS2769, measured on TypeScript 5.9.3) once the one-language
|
|
178
|
-
* overload existed, although this signature alone accepted it. A typed `t` missing a key is
|
|
179
|
-
*
|
|
178
|
+
* overload existed, although this signature alone accepted it. A typed `t` missing a key is still
|
|
179
|
+
* refused.
|
|
180
180
|
*/
|
|
181
181
|
t: Translate<NoInfer<`${Prefix}${CopyName}` | `${ServerPrefix}${ServerName | PluralBase<ServerName>}`>>;
|
|
182
182
|
/** Catalog namespace for this module's own copy, e.g. `"errors."`. */
|
|
183
183
|
copyPrefix: Prefix;
|
|
184
184
|
/**
|
|
185
185
|
* The server's own catalog namespace, e.g. `"serverErrors."`. A `messageKey` outside it is
|
|
186
|
-
* ignored
|
|
186
|
+
* ignored. The server names a sentence, it does not get to name any key in the app.
|
|
187
187
|
*
|
|
188
|
-
* The `code` is read under this prefix too, for an API that has no `messageKey` field and
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
188
|
+
* The `code` is read under this prefix too, for an API that has no `messageKey` field and lets
|
|
189
|
+
* the code name the sentence. One repo in the fleet has 98 of those, `errors.NOT_FOUND` and its
|
|
190
|
+
* siblings, against another repo's `messageKey`. Both are the same claim ("the server named a
|
|
191
|
+
* sentence this app carries"), both pass the same gate below, and an app that uses neither is
|
|
192
|
+
* unaffected because nothing matches.
|
|
193
193
|
*/
|
|
194
194
|
messageKeyPrefix: ServerPrefix;
|
|
195
195
|
/**
|
|
@@ -197,13 +197,13 @@ export interface ErrorDescriberOptions<Prefix extends string, ServerPrefix exten
|
|
|
197
197
|
* catalog. Passing the catalog itself is both the membership test and the proof the compiler
|
|
198
198
|
* wants: a name that is in it IS a key, so the lookup below needs no cast.
|
|
199
199
|
*
|
|
200
|
-
* It is required because leaving it out
|
|
201
|
-
*
|
|
200
|
+
* It is required because leaving it out reintroduces the bug the option exists to prevent rather
|
|
201
|
+
* than making this smaller. i18next answers a key it does not have with the key itself, so a
|
|
202
202
|
* deploy landing ahead of the bundle a tab is still running would render `serverErrors.foo` at
|
|
203
203
|
* somebody. A name that is absent falls back to the server's English `message` instead.
|
|
204
204
|
*
|
|
205
|
-
* Hand it over as it is. A plural sits in the catalog under suffixed names while the server
|
|
206
|
-
*
|
|
205
|
+
* Hand it over as it is. A plural sits in the catalog under suffixed names while the server names
|
|
206
|
+
* the base, so the base is admitted too. See {@link PluralBase}.
|
|
207
207
|
*/
|
|
208
208
|
knownMessageKeys: Record<ServerName, unknown>;
|
|
209
209
|
/**
|
|
@@ -211,13 +211,13 @@ export interface ErrorDescriberOptions<Prefix extends string, ServerPrefix exten
|
|
|
211
211
|
*
|
|
212
212
|
* The envelope carries what the SERVER knows, which is not always a word anyone should read: a
|
|
213
213
|
* role id (`admin`), an action verb (`approve_content`). The sentence needs whatever the app's
|
|
214
|
-
* own screens call those things, and the substitution happens here
|
|
215
|
-
* reads `params
|
|
216
|
-
*
|
|
217
|
-
*
|
|
214
|
+
* own screens call those things, and the substitution happens here, inside the one lookup that
|
|
215
|
+
* reads `params`. There is nowhere else an adopter could intervene. Without this seam the choice
|
|
216
|
+
* is to ship the raw id into `{{role}}`, or to stop using the server's sentence at all and
|
|
217
|
+
* re-resolve every key by hand, which is how i18n ended up inside a transport once already.
|
|
218
218
|
*
|
|
219
219
|
* Optional, and identity by default: an API whose params are already words passes nothing. It
|
|
220
|
-
* deliberately takes only the params
|
|
220
|
+
* deliberately takes only the params. An arm that needs the error has `ctx` for that.
|
|
221
221
|
*/
|
|
222
222
|
localizeParams?: (params: Record<string, string | number> | undefined) => Record<string, unknown> | undefined;
|
|
223
223
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-error.d.ts","sourceRoot":"","sources":["../src/describe-error.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY;AACtB,mDAAmD;AACjD,OAAO;AACT,gEAAgE;GAC9D,QAAQ;AACV,gFAAgF;GAC9E,MAAM;AACR,iFAAiF;GAC/E,MAAM,CAAC;AAEX,+FAA+F;AAC/F,MAAM,WAAW,SAAS;IACxB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,
|
|
1
|
+
{"version":3,"file":"describe-error.d.ts","sourceRoot":"","sources":["../src/describe-error.ts"],"names":[],"mappings":"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"}
|
package/dist/describe-error.js
CHANGED
|
@@ -3,17 +3,17 @@ import { ApiError } from "./api-error.js";
|
|
|
3
3
|
import { shouldRetry } from "./query.js";
|
|
4
4
|
const PLURAL_SUFFIX = /_(zero|one|two|few|many|other)$/;
|
|
5
5
|
/**
|
|
6
|
-
* "in 4 minutes"
|
|
6
|
+
* Format a wait as "in 4 minutes" or "in 2 hours", without making the reader convert seconds.
|
|
7
7
|
*
|
|
8
8
|
* The thresholds are deliberately not round: 90 seconds rather than 60, so "in 75 seconds" does
|
|
9
9
|
* not become the less precise "in 1 minute", and 90 minutes rather than 60 for the same reason
|
|
10
10
|
* one rung up. Needs `waitSeconds` / `waitMinutes` / `waitHours` under `prefix`, each with a
|
|
11
11
|
* `count` plural.
|
|
12
12
|
*
|
|
13
|
-
* This is what you pass as `formatWait` when your catalog carries those three:
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* This is what you pass as `formatWait` when your catalog carries those three: `formatWait: (secs)
|
|
14
|
+
* => humanizeWait(t, secs, "errors.")`. An app that formats a wait with `Intl.RelativeTimeFormat`
|
|
15
|
+
* passes its own one-liner instead and needs no wait keys at all. It also gets correct plurals in
|
|
16
|
+
* languages with more than two forms, for free.
|
|
17
17
|
*/
|
|
18
18
|
export function humanizeWait(t, secs, prefix) {
|
|
19
19
|
// Up, never to the nearest: a wait is a floor, and "in 2 hours" for 2h24 sends the reader back
|
package/dist/error-boundary.d.ts
CHANGED
|
@@ -2,27 +2,27 @@ import { Component, type ErrorInfo, type ReactNode } from "react";
|
|
|
2
2
|
/**
|
|
3
3
|
* The last stop before a white screen.
|
|
4
4
|
*
|
|
5
|
-
* React unmounts the whole tree when a render throws, and an app with no boundary anywhere
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* React unmounts the whole tree when a render throws, and an app with no boundary anywhere answers
|
|
6
|
+
* that with a blank page: no words, no navigation, no reload. That is the most complete dead end a
|
|
7
|
+
* product can produce, and the one the never-dead-end rule cannot reach, because by then there is
|
|
8
|
+
* no component left to render a state from.
|
|
9
9
|
*
|
|
10
10
|
* It is deliberately dumb. No retry loop, no error reporting, no reset on a timer: it catches,
|
|
11
11
|
* it hands the error to a `fallback` the app draws in its own words, and it offers `reset`.
|
|
12
12
|
* Every donor that baked its own UI in here had to keep a second copy for its second surface;
|
|
13
13
|
* a render prop has no such problem, and the brand stays in the product where it belongs.
|
|
14
14
|
*
|
|
15
|
-
* A class, because `getDerivedStateFromError` has no hook equivalent
|
|
16
|
-
*
|
|
15
|
+
* A class, because `getDerivedStateFromError` has no hook equivalent. This is the one thing in the
|
|
16
|
+
* kit React still has no other way to express.
|
|
17
17
|
*/
|
|
18
18
|
export interface ErrorBoundaryFallbackProps {
|
|
19
19
|
error: Error;
|
|
20
20
|
/** Put the children back. */
|
|
21
21
|
reset: () => void;
|
|
22
22
|
/**
|
|
23
|
-
* True when the throw was a failed lazy-chunk import
|
|
24
|
-
* open, so the fix is a reload and NOT a retry (a rejected dynamic import rethrows on
|
|
25
|
-
*
|
|
23
|
+
* True when the throw was a failed lazy-chunk import because a deploy landed while this tab was
|
|
24
|
+
* open, so the fix is a reload and NOT a retry (a rejected dynamic import rethrows on re-render
|
|
25
|
+
* forever). Draw the "updating" screen, not the crash screen.
|
|
26
26
|
*/
|
|
27
27
|
isChunkError: boolean;
|
|
28
28
|
}
|
|
@@ -30,9 +30,9 @@ export interface ErrorBoundaryProps {
|
|
|
30
30
|
/** Drawn instead of the children once something has thrown. */
|
|
31
31
|
fallback: (props: ErrorBoundaryFallbackProps) => ReactNode;
|
|
32
32
|
/**
|
|
33
|
-
* Changing this value clears the error and remounts the children
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* Changing this value clears the error and remounts the children. Pass the route, so navigating
|
|
34
|
+
* away from a screen that broke actually leaves it rather than carrying its wreckage to every
|
|
35
|
+
* page after it.
|
|
36
36
|
*/
|
|
37
37
|
resetKey?: string;
|
|
38
38
|
/** Called once per catch. Report to whatever the app reports to. */
|
package/dist/guards.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
/**
|
|
3
3
|
* Route guards.
|
|
4
4
|
*
|
|
5
|
-
* Two donors wrote these four, gave two of them the same names, and explained them in nearly
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Two donors wrote these four, gave two of them the same names, and explained them in nearly the
|
|
6
|
+
* same words. What differed was one line. That line is invariant 4, so it is the reason this file
|
|
7
|
+
* exists rather than being copied a ninth time.
|
|
8
8
|
*
|
|
9
9
|
* These are factories because the destinations are the app's: `paths.signIn` is not something a
|
|
10
10
|
* package can know, and one donor hardcoded `/login` in four places for exactly that reason.
|
|
@@ -21,18 +21,18 @@ export interface SessionState {
|
|
|
21
21
|
/**
|
|
22
22
|
* The answer to a "who is this?" query, in the three states it actually has.
|
|
23
23
|
*
|
|
24
|
-
* This shape is invariant 4. A guard reading `!me?.isStaff` collapses "pending", "failed" and
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* This shape is invariant 4. A guard reading `!me?.isStaff` collapses "pending", "failed" and "no"
|
|
25
|
+
* into one branch, so an operator arriving while `/auth/me` is 500ing is told the page does not
|
|
26
|
+
* exist. Wrong cause, no retry, and no request id to quote to support. One donor hit that and fixed
|
|
27
|
+
* it; the other still has the collapsed version.
|
|
28
28
|
*
|
|
29
29
|
* `"pending"` and not `"loading"` for one measured reason: it is react-query's own word for this
|
|
30
30
|
* state since v5, and with the words matching a `UseQueryResult<TMe>` satisfies this type
|
|
31
|
-
* STRUCTURALLY
|
|
32
|
-
* `"loading"` it does not typecheck and every adopter hand-writes the same six-line mapping;
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* STRUCTURALLY: `createRequireProfile(useMe, …)` takes the hook directly, no adapter. With
|
|
32
|
+
* `"loading"` it does not typecheck and every adopter hand-writes the same six-line mapping; eight
|
|
33
|
+
* of the twelve repos this serves are on react-query, and the first migration wrote that mapping
|
|
34
|
+
* before anyone noticed. Nothing here imports react-query at runtime. The type stays structural, so
|
|
35
|
+
* an app on SWR or a plain `useState` still answers it in three lines.
|
|
36
36
|
*/
|
|
37
37
|
export type MeQuery<TMe> = {
|
|
38
38
|
status: "pending";
|
|
@@ -50,8 +50,8 @@ export interface GuardOptions {
|
|
|
50
50
|
/** Query parameter carrying the route a sign-in interrupted. */
|
|
51
51
|
export declare const AUTH_RETURN_PARAM = "next";
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* Require sign-in and remember where they were headed, so the redirect afterwards lands on the page
|
|
54
|
+
* they actually wanted rather than the home screen.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createRequireAuth(useSession: () => SessionState, signInPath: string, { loading }: GuardOptions): ({ children }: {
|
|
57
57
|
children: ReactNode;
|
|
@@ -61,7 +61,7 @@ export declare function createRequireAnonymous(useSession: () => SessionState, h
|
|
|
61
61
|
children: ReactNode;
|
|
62
62
|
}) => import("react").JSX.Element;
|
|
63
63
|
/**
|
|
64
|
-
* A gate on
|
|
64
|
+
* A gate on a profile field, such as whether the person is suspended, staff or on a given plan.
|
|
65
65
|
*
|
|
66
66
|
* `allow` gets the profile and answers yes or no. `onDenied` draws the refusal; `onError` draws
|
|
67
67
|
* the failure, and they are SEPARATE arguments on purpose. That separation is the whole point
|
package/dist/guards.js
CHANGED
|
@@ -8,8 +8,8 @@ function signInUrl(signInPath, returnTo) {
|
|
|
8
8
|
return `${signInPath}${separator}${AUTH_RETURN_PARAM}=${encodeURIComponent(returnTo)}`;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Require sign-in and remember where they were headed, so the redirect afterwards lands on the page
|
|
12
|
+
* they actually wanted rather than the home screen.
|
|
13
13
|
*/
|
|
14
14
|
export function createRequireAuth(useSession, signInPath, { loading }) {
|
|
15
15
|
return function RequireAuth({ children }) {
|
|
@@ -46,7 +46,7 @@ export function createRequireAnonymous(useSession, homePath, { loading }) {
|
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* A gate on
|
|
49
|
+
* A gate on a profile field, such as whether the person is suspended, staff or on a given plan.
|
|
50
50
|
*
|
|
51
51
|
* `allow` gets the profile and answers yes or no. `onDenied` draws the refusal; `onError` draws
|
|
52
52
|
* the failure, and they are SEPARATE arguments on purpose. That separation is the whole point
|
package/dist/hydrate.d.ts
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The browser half of prerendering: deciding whether to hydrate or to mount fresh.
|
|
3
3
|
*
|
|
4
|
-
* Three separate repos invented all of this independently
|
|
5
|
-
* value
|
|
6
|
-
* deduping; it is one lesson learned three times, and it belongs somewhere it can be learned
|
|
7
|
-
* once.
|
|
4
|
+
* Three separate repos invented all of this independently, with the same constant name, string
|
|
5
|
+
* value and decision, and near-identical explaining comments. That is not a coincidence worth
|
|
6
|
+
* deduping; it is one lesson learned three times, and it belongs somewhere it can be learned once.
|
|
8
7
|
*
|
|
9
8
|
* The constants themselves live in `prerender-contract.ts`, which imports nothing, because the
|
|
10
9
|
* BUILD needs them too and must not pull `react-dom/client` into a Node process to get a string.
|
|
11
10
|
*
|
|
12
11
|
* This module sits behind `@gusnips/react/hydrate` rather than in the barrel for the same reason
|
|
13
|
-
* one rung further out: it is the package's ONLY `react-dom` import, and a React Native app has
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* one rung further out: it is the package's ONLY `react-dom` import, and a React Native app has no
|
|
13
|
+
* react-dom to give. Leaving it in the barrel made `react-dom` a required peer and shut the whole
|
|
14
|
+
* package out of every phone for one function a phone would never call.
|
|
16
15
|
*/
|
|
17
16
|
import type { ReactNode } from "react";
|
|
18
17
|
export { PRERENDERED_ROUTE_ATTR, SHELL_ROUTE } from "./prerender-contract.ts";
|
|
@@ -20,16 +19,16 @@ export { PRERENDERED_ROUTE_ATTR, SHELL_ROUTE } from "./prerender-contract.ts";
|
|
|
20
19
|
* Hydrate the render this file IS, and mount fresh over anything else.
|
|
21
20
|
*
|
|
22
21
|
* "Does the root have children" is the wrong question, and getting it wrong is silent. A static
|
|
23
|
-
* host answers every address it does not publish with the nearest `404.html
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* host answers every address it does not publish with the nearest `404.html`, which has the
|
|
23
|
+
* not-found page rendered INTO it. An address served from a shell arrives at a full root holding
|
|
24
|
+
* somebody else's markup. Hydrating that is React reconciling two different pages: it recovers by
|
|
25
|
+
* throwing the whole tree away and says so in the console, which is a page that works and a bug
|
|
26
|
+
* nobody sees. The file names the route it is a render of, so we can simply ask.
|
|
28
27
|
*
|
|
29
|
-
* `route` is passed in rather than read from `window.location` on purpose. A localized app
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
28
|
+
* `route` is passed in rather than read from `window.location` on purpose. A localized app serves
|
|
29
|
+
* `/pt/pricing` from a file rendered for `/pricing`, with the locale carried in the router's
|
|
30
|
+
* `basename`, so the address and the route are different strings, and only the caller knows which
|
|
31
|
+
* one the build wrote.
|
|
33
32
|
*
|
|
34
33
|
* **A trailing slash is not a different page.** The router renders `/precos/` and `/precos` alike,
|
|
35
34
|
* and which one is in the address bar is the host's call: a host serving `precos/index.html`
|
package/dist/hydrate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAI3F"}
|
package/dist/hydrate.js
CHANGED
|
@@ -5,16 +5,16 @@ export { PRERENDERED_ROUTE_ATTR, SHELL_ROUTE } from "./prerender-contract.js";
|
|
|
5
5
|
* Hydrate the render this file IS, and mount fresh over anything else.
|
|
6
6
|
*
|
|
7
7
|
* "Does the root have children" is the wrong question, and getting it wrong is silent. A static
|
|
8
|
-
* host answers every address it does not publish with the nearest `404.html
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* host answers every address it does not publish with the nearest `404.html`, which has the
|
|
9
|
+
* not-found page rendered INTO it. An address served from a shell arrives at a full root holding
|
|
10
|
+
* somebody else's markup. Hydrating that is React reconciling two different pages: it recovers by
|
|
11
|
+
* throwing the whole tree away and says so in the console, which is a page that works and a bug
|
|
12
|
+
* nobody sees. The file names the route it is a render of, so we can simply ask.
|
|
13
13
|
*
|
|
14
|
-
* `route` is passed in rather than read from `window.location` on purpose. A localized app
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* `route` is passed in rather than read from `window.location` on purpose. A localized app serves
|
|
15
|
+
* `/pt/pricing` from a file rendered for `/pricing`, with the locale carried in the router's
|
|
16
|
+
* `basename`, so the address and the route are different strings, and only the caller knows which
|
|
17
|
+
* one the build wrote.
|
|
18
18
|
*
|
|
19
19
|
* **A trailing slash is not a different page.** The router renders `/precos/` and `/precos` alike,
|
|
20
20
|
* and which one is in the address bar is the host's call: a host serving `precos/index.html`
|
package/dist/hydrate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,cAAc,CAAC,MAAe,EAAE,IAAe,EAAE,KAAoB;IACnF,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC;IAC7D,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;;QAC3F,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,4DAA4D;AAC5D,SAAS,QAAQ,CAAC,CAAS,EAAE,CAAS;IACpC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACrE,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC"}
|
package/dist/i18n.d.ts
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
* ```
|
|
9
9
|
*
|
|
10
10
|
* Keeping the options here is what stops a console, a storefront and a docs site in the same
|
|
11
|
-
* product from drifting apart on the details below
|
|
12
|
-
* shipped.
|
|
11
|
+
* product from drifting apart on the details below. Each is a bug somebody already shipped.
|
|
13
12
|
*/
|
|
14
13
|
export interface I18nInitOptions {
|
|
15
14
|
/** The language everything falls back to. */
|
|
@@ -27,10 +26,10 @@ export interface I18nInitOptions {
|
|
|
27
26
|
/**
|
|
28
27
|
* The query parameter that hands a language ACROSS an origin, e.g. `"lang"`.
|
|
29
28
|
*
|
|
30
|
-
* When set it is detected FIRST, ahead of storage and the browser
|
|
29
|
+
* When set it is detected FIRST, ahead of storage and the browser. It is the only one of the
|
|
31
30
|
* three that somebody chose on purpose and just now. A reader who picked Português on the
|
|
32
|
-
* storefront and followed a link into the app means it more than their laptop's locale does.
|
|
33
|
-
*
|
|
31
|
+
* storefront and followed a link into the app means it more than their laptop's locale does. It
|
|
32
|
+
* is cached on arrival, so it decides once and no URL inside the app has to carry it.
|
|
34
33
|
*
|
|
35
34
|
* Only one donor had this. The other has the same split-origin layout and the same problem.
|
|
36
35
|
*/
|
|
@@ -38,15 +37,15 @@ export interface I18nInitOptions {
|
|
|
38
37
|
/**
|
|
39
38
|
* Who WRITES {@link storageKey}. The detector, by default.
|
|
40
39
|
*
|
|
41
|
-
* Pass `"app"` when your own language control writes it.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
40
|
+
* Pass `"app"` when your own language control writes it. A "follow the browser" option needs
|
|
41
|
+
* this. Going back to following the browser means clearing the key and calling
|
|
42
|
+
* `changeLanguage(undefined)`, which re-runs detection; a detector that caches then writes the
|
|
43
|
+
* language it just detected straight back into the key it was told to clear. The choice re-pins
|
|
44
|
+
* itself and nothing can reach that state again.
|
|
46
45
|
*
|
|
47
46
|
* Three repos on this stack, three answers: one lets the detector write, one writes it from its
|
|
48
|
-
* own control, and one does both
|
|
49
|
-
* browser" state. So the rule, rather than the default: one writer per key.
|
|
47
|
+
* own control, and one does both. Doing both is harmless there only because it offers no "follow
|
|
48
|
+
* the browser" state. So the rule, rather than the default: one writer per key.
|
|
50
49
|
*/
|
|
51
50
|
storageWriter?: "detector" | "app";
|
|
52
51
|
}
|
|
@@ -73,13 +72,13 @@ export declare function i18nInitOptions({ fallbackLng, supportedLngs, storageKey
|
|
|
73
72
|
* i18next ever sees it.
|
|
74
73
|
*
|
|
75
74
|
* Done here rather than through interpolation because i18next v26 has no global interpolation
|
|
76
|
-
* defaults, and these strings are often resolved by dynamic key
|
|
75
|
+
* defaults, and these strings are often resolved by dynamic key, so a wrapping `t()` would not
|
|
77
76
|
* reach them. The point is that a rename or a domain move is ONE edit in the brand constants
|
|
78
77
|
* instead of a sweep across every locale file.
|
|
79
78
|
*
|
|
80
|
-
* Returns a fresh tree; the input is untouched. The placeholder names come from `vars`, so
|
|
81
|
-
*
|
|
82
|
-
*
|
|
79
|
+
* Returns a fresh tree; the input is untouched. The placeholder names come from `vars`, so adding
|
|
80
|
+
* one needs no change here. Two donors hardcoded their own list in the regex and both had to
|
|
81
|
+
* remember to update it.
|
|
83
82
|
*/
|
|
84
83
|
export declare function applyBrandVars<T>(resources: T, vars: Record<string, string>): T;
|
|
85
84
|
//# sourceMappingURL=i18n.d.ts.map
|
package/dist/i18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;CACpC;AAED,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,aAAa,EACb,UAAU,EACV,QAAQ,EACR,aAA0B,GAC3B,EAAE,eAAe;;;;;;;;;uCAOK,MAAM,KAAG,MAAM;;;;;;;;EAkCrC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAmB/E"}
|