@pithy-sh/core 0.8.0 → 0.9.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/dist/naming/domains.d.ts +13 -0
- package/dist/naming/domains.d.ts.map +1 -1
- package/dist/naming/domains.js +22 -1
- package/dist/seed/devLogin.d.ts +33 -0
- package/dist/seed/devLogin.d.ts.map +1 -1
- package/dist/seed/devLogin.js +28 -1
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/package.json +1 -1
- package/src/naming/domains.ts +23 -1
- package/src/seed/devLogin.ts +31 -0
- package/src/version.generated.ts +1 -1
package/dist/naming/domains.d.ts
CHANGED
|
@@ -9,6 +9,19 @@ import { type AmbientEnv } from "../env/ambient";
|
|
|
9
9
|
*
|
|
10
10
|
* The one test for "is this a host" that an origin read from a stamp and an origin typed on a command line
|
|
11
11
|
* both pass, so the two cannot accept different things.
|
|
12
|
+
*
|
|
13
|
+
* **It answers the same on every runtime, and that is why the punycode rule is stated here.** It used to be
|
|
14
|
+
* borrowed: `seedHostOrigin` asked `new URL` to parse the host and took a throw as the answer, and an invalid
|
|
15
|
+
* A-label like `xn--a.test` was refused because the parser refused it. Node 24.20.0 bumped Ada from 3.4.4 to
|
|
16
|
+
* 4.0.0, Ada 4 stopped rejecting invalid punycode, and the same `pithy seed --host` began succeeding on Node 24
|
|
17
|
+
* while still failing on Node 22 — one command, two answers, decided by the adopter's Node. A rule borrowed from
|
|
18
|
+
* a parser changes under you, so this owns it.
|
|
19
|
+
*
|
|
20
|
+
* **Every A-label is refused, valid or not.** Telling a good one from a bad one is UTS-46, which needs IDNA
|
|
21
|
+
* mapping tables this package is not carrying into a Worker for the sake of a hostname check — and
|
|
22
|
+
* {@link HOSTNAME_PATTERN} is ASCII-only anyway, so a Unicode domain never reached here to begin with. This
|
|
23
|
+
* closes the hand-encoded spelling, and internationalized domains are a feature with a specification behind
|
|
24
|
+
* them rather than a side effect of a parser version.
|
|
12
25
|
*/
|
|
13
26
|
export declare function isPublicHostname(hostname: string): boolean;
|
|
14
27
|
/** The environments a domain may be declared for — every managed one, never `dev`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/naming/domains.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/naming/domains.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,gBAAgB,CAAC;AAgD7D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,wBAA8D,CAAC;AAE/F,uDAAuD;AACvD,eAAO,MAAM,YAAY;;;iBA+BrB,CAAC;AACL,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;GAKG;AACH,eAAO,MAAM,aAAa;;;;;;;;;iBAOvB,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAKlH;AAED,gHAAgH;AAChH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEvD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAetG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAC3B,cAAc,CAShB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,GAAG,GAAE,UAAyB,GAC7B,MAAM,CAER"}
|
package/dist/naming/domains.js
CHANGED
|
@@ -39,15 +39,36 @@ import { z } from "zod";
|
|
|
39
39
|
/** A hostname a Worker answers on. No scheme, no path, no port — wrangler's `routes` pattern is a host. */
|
|
40
40
|
const HOSTNAME_PATTERN = /^(?!-)[a-z0-9-]{1,63}(?<!-)(\.(?!-)[a-z0-9-]{1,63}(?<!-))+$/;
|
|
41
41
|
/**
|
|
42
|
+
* **A label that is a punycode A-label — the ASCII spelling of an internationalized name.**
|
|
43
|
+
*
|
|
44
|
+
* Anchored to a label boundary, so it is `xn--a.test` and `example.xn--p1ai` and never `myxn--a.test`:
|
|
45
|
+
* a name that merely reads that way is an ordinary name, and refusing it would be this rule reaching
|
|
46
|
+
* past what it is about.
|
|
47
|
+
*/
|
|
48
|
+
const PUNYCODE_LABEL = /(^|\.)xn--/;
|
|
49
|
+
/**
|
|
42
50
|
* Whether a string is a public hostname: dot-separated DNS labels, at least two, lowercase. No scheme, no
|
|
43
51
|
* port, no trailing dot, and nothing a URL parser decoded into one — `%2e%2e` is `..` once parsed, which is an
|
|
44
52
|
* empty label rather than a host (#643). `localhost` is not one: it has a single label, and it is this machine.
|
|
45
53
|
*
|
|
46
54
|
* The one test for "is this a host" that an origin read from a stamp and an origin typed on a command line
|
|
47
55
|
* both pass, so the two cannot accept different things.
|
|
56
|
+
*
|
|
57
|
+
* **It answers the same on every runtime, and that is why the punycode rule is stated here.** It used to be
|
|
58
|
+
* borrowed: `seedHostOrigin` asked `new URL` to parse the host and took a throw as the answer, and an invalid
|
|
59
|
+
* A-label like `xn--a.test` was refused because the parser refused it. Node 24.20.0 bumped Ada from 3.4.4 to
|
|
60
|
+
* 4.0.0, Ada 4 stopped rejecting invalid punycode, and the same `pithy seed --host` began succeeding on Node 24
|
|
61
|
+
* while still failing on Node 22 — one command, two answers, decided by the adopter's Node. A rule borrowed from
|
|
62
|
+
* a parser changes under you, so this owns it.
|
|
63
|
+
*
|
|
64
|
+
* **Every A-label is refused, valid or not.** Telling a good one from a bad one is UTS-46, which needs IDNA
|
|
65
|
+
* mapping tables this package is not carrying into a Worker for the sake of a hostname check — and
|
|
66
|
+
* {@link HOSTNAME_PATTERN} is ASCII-only anyway, so a Unicode domain never reached here to begin with. This
|
|
67
|
+
* closes the hand-encoded spelling, and internationalized domains are a feature with a specification behind
|
|
68
|
+
* them rather than a side effect of a parser version.
|
|
48
69
|
*/
|
|
49
70
|
function isPublicHostname(hostname) {
|
|
50
|
-
return hostname.length <= 253 && HOSTNAME_PATTERN.test(hostname);
|
|
71
|
+
return hostname.length <= 253 && HOSTNAME_PATTERN.test(hostname) && !PUNYCODE_LABEL.test(hostname);
|
|
51
72
|
}
|
|
52
73
|
/** The environments a domain may be declared for — every managed one, never `dev`. */
|
|
53
74
|
const DOMAIN_ENVIRONMENTS = ENVIRONMENTS.filter((environment) => environment !== "dev");
|
package/dist/seed/devLogin.d.ts
CHANGED
|
@@ -56,4 +56,37 @@ export declare const DevLogin: z.ZodObject<{
|
|
|
56
56
|
expiresAt: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>;
|
|
57
57
|
}, z.core.$strip>;
|
|
58
58
|
export type DevLogin = z.output<typeof DevLogin>;
|
|
59
|
+
/**
|
|
60
|
+
* Every seeded dev login, keyed by `userId` — what `logs/dev-login.json` holds.
|
|
61
|
+
*
|
|
62
|
+
* **One entry per user the seed creates — `#667`.** It used to hold exactly one, named by a per-machine
|
|
63
|
+
* `dev.json`, so being a second seeded user meant reseeding or minting a claim by hand. Both are slow
|
|
64
|
+
* enough that people stop doing it, and the screens only one user can reach stop getting looked at. A
|
|
65
|
+
* claim is a signature over a user id and an expiry, so N of them cost no extra seeded rows and a few
|
|
66
|
+
* hundred bytes each.
|
|
67
|
+
*
|
|
68
|
+
* The key is the `userId`, which each entry also carries: the key is how the record is addressed and the
|
|
69
|
+
* field is what an entry means on its own, once something has picked one out of here.
|
|
70
|
+
*
|
|
71
|
+
* **Order is the file's, and for integer-like ids the language's.** `pithy dev` offers the identities in the
|
|
72
|
+
* order they are read, which is insertion order — except that JS enumerates canonical array-index keys
|
|
73
|
+
* first, in ascending numeric order, so a project whose user ids are stringified integers gets them
|
|
74
|
+
* numerically however the seed wrote them. Nothing depends on the order being the seed's; it is an offer
|
|
75
|
+
* order, not an identity.
|
|
76
|
+
*
|
|
77
|
+
* **The whole file is still one live credential, and the three properties that made one acceptable are
|
|
78
|
+
* what make N acceptable** — `logs/` is gitignored by the starter template, the artifact is written
|
|
79
|
+
* `0600`, and the writer refuses a symlink at the target.
|
|
80
|
+
*
|
|
81
|
+
* **Nothing migrates.** The single-entry file this replaced has strings where an entry belongs, so it does
|
|
82
|
+
* not parse, and every reader already answers "no dev login" to a file that does not — the banner stays
|
|
83
|
+
* quiet until the next `pithy seed`. The artifact is gitignored and regenerated, so that is the plan.
|
|
84
|
+
*/
|
|
85
|
+
export declare const DevLogins: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
86
|
+
email: z.ZodString;
|
|
87
|
+
userId: z.ZodString;
|
|
88
|
+
claim: z.ZodString;
|
|
89
|
+
expiresAt: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>;
|
|
90
|
+
}, z.core.$strip>>;
|
|
91
|
+
export type DevLogins = z.output<typeof DevLogins>;
|
|
59
92
|
//# sourceMappingURL=devLogin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devLogin.d.ts","sourceRoot":"","sources":["../../src/seed/devLogin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;;;;;;GAkBG;AAEH,2GAA2G;AAC3G,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC,gHAAgH;AAChH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,uGAAuG;AACvG,eAAO,MAAM,cAAc,wBAA2C,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,uBAAuB,CAAC;AAEpD,uGAAuG;AACvG,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;;;iBAWqF,CAAC;AAC3G,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"devLogin.d.ts","sourceRoot":"","sources":["../../src/seed/devLogin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;;;;;;GAkBG;AAEH,2GAA2G;AAC3G,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC,gHAAgH;AAChH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,uGAAuG;AACvG,eAAO,MAAM,cAAc,wBAA2C,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,uBAAuB,CAAC;AAEpD,uGAAuG;AACvG,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;;;iBAWqF,CAAC;AAC3G,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,SAAS;;;;;kBAEuE,CAAC;AAC9F,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC"}
|
package/dist/seed/devLogin.js
CHANGED
|
@@ -57,5 +57,32 @@ const DevLogin = z.object({
|
|
|
57
57
|
claim: z.string().describe("The signed, URI-encoded claim naming the user to sign in as. A live credential for the local database — never logged, never committed, never in an error payload. **Not a session:** it names a user and the route mints a session against it, so revoking a session leaves it working."),
|
|
58
58
|
expiresAt: JsonDate.describe("When the claim stops being accepted. ISO-8601 text on disk; a `Date` in app code.")
|
|
59
59
|
}).describe("A seeded dev login: the signed claim for one seeded user, written to `logs/dev-login.json`.");
|
|
60
|
+
/**
|
|
61
|
+
* Every seeded dev login, keyed by `userId` — what `logs/dev-login.json` holds.
|
|
62
|
+
*
|
|
63
|
+
* **One entry per user the seed creates — `#667`.** It used to hold exactly one, named by a per-machine
|
|
64
|
+
* `dev.json`, so being a second seeded user meant reseeding or minting a claim by hand. Both are slow
|
|
65
|
+
* enough that people stop doing it, and the screens only one user can reach stop getting looked at. A
|
|
66
|
+
* claim is a signature over a user id and an expiry, so N of them cost no extra seeded rows and a few
|
|
67
|
+
* hundred bytes each.
|
|
68
|
+
*
|
|
69
|
+
* The key is the `userId`, which each entry also carries: the key is how the record is addressed and the
|
|
70
|
+
* field is what an entry means on its own, once something has picked one out of here.
|
|
71
|
+
*
|
|
72
|
+
* **Order is the file's, and for integer-like ids the language's.** `pithy dev` offers the identities in the
|
|
73
|
+
* order they are read, which is insertion order — except that JS enumerates canonical array-index keys
|
|
74
|
+
* first, in ascending numeric order, so a project whose user ids are stringified integers gets them
|
|
75
|
+
* numerically however the seed wrote them. Nothing depends on the order being the seed's; it is an offer
|
|
76
|
+
* order, not an identity.
|
|
77
|
+
*
|
|
78
|
+
* **The whole file is still one live credential, and the three properties that made one acceptable are
|
|
79
|
+
* what make N acceptable** — `logs/` is gitignored by the starter template, the artifact is written
|
|
80
|
+
* `0600`, and the writer refuses a symlink at the target.
|
|
81
|
+
*
|
|
82
|
+
* **Nothing migrates.** The single-entry file this replaced has strings where an entry belongs, so it does
|
|
83
|
+
* not parse, and every reader already answers "no dev login" to a file that does not — the banner stays
|
|
84
|
+
* quiet until the next `pithy seed`. The artifact is gitignored and regenerated, so that is the plan.
|
|
85
|
+
*/
|
|
86
|
+
const DevLogins = z.record(z.string(), DevLogin).describe("Every seeded dev login, keyed by user id, as `logs/dev-login.json` holds them.");
|
|
60
87
|
//#endregion
|
|
61
|
-
export { DEV_LOGIN_CLAIM_PARAM, DEV_LOGIN_FILE, DEV_LOGIN_PATH, DEV_LOGIN_ROUTE, DevLogin, SEED_ARTIFACT_DIR };
|
|
88
|
+
export { DEV_LOGIN_CLAIM_PARAM, DEV_LOGIN_FILE, DEV_LOGIN_PATH, DEV_LOGIN_ROUTE, DevLogin, DevLogins, SEED_ARTIFACT_DIR };
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
/** This package's npm name — the join key against a release feed. */
|
|
4
4
|
export declare const PACKAGE_NAME = "@pithy-sh/core";
|
|
5
5
|
/** This package's version, stamped from its own package.json at generation time. */
|
|
6
|
-
export declare const PACKAGE_VERSION = "0.
|
|
6
|
+
export declare const PACKAGE_VERSION = "0.9.0";
|
|
7
7
|
//# sourceMappingURL=version.generated.d.ts.map
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
/** This package's npm name — the join key against a release feed. */
|
|
5
5
|
const PACKAGE_NAME = "@pithy-sh/core";
|
|
6
6
|
/** This package's version, stamped from its own package.json at generation time. */
|
|
7
|
-
const PACKAGE_VERSION = "0.
|
|
7
|
+
const PACKAGE_VERSION = "0.9.0";
|
|
8
8
|
//#endregion
|
|
9
9
|
export { PACKAGE_NAME, PACKAGE_VERSION };
|
package/package.json
CHANGED
package/src/naming/domains.ts
CHANGED
|
@@ -41,6 +41,15 @@ import { ENVIRONMENTS, FEATURE_ENVIRONMENT } from "./environment";
|
|
|
41
41
|
/** A hostname a Worker answers on. No scheme, no path, no port — wrangler's `routes` pattern is a host. */
|
|
42
42
|
const HOSTNAME_PATTERN = /^(?!-)[a-z0-9-]{1,63}(?<!-)(\.(?!-)[a-z0-9-]{1,63}(?<!-))+$/;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* **A label that is a punycode A-label — the ASCII spelling of an internationalized name.**
|
|
46
|
+
*
|
|
47
|
+
* Anchored to a label boundary, so it is `xn--a.test` and `example.xn--p1ai` and never `myxn--a.test`:
|
|
48
|
+
* a name that merely reads that way is an ordinary name, and refusing it would be this rule reaching
|
|
49
|
+
* past what it is about.
|
|
50
|
+
*/
|
|
51
|
+
const PUNYCODE_LABEL = /(^|\.)xn--/;
|
|
52
|
+
|
|
44
53
|
/**
|
|
45
54
|
* Whether a string is a public hostname: dot-separated DNS labels, at least two, lowercase. No scheme, no
|
|
46
55
|
* port, no trailing dot, and nothing a URL parser decoded into one — `%2e%2e` is `..` once parsed, which is an
|
|
@@ -48,9 +57,22 @@ const HOSTNAME_PATTERN = /^(?!-)[a-z0-9-]{1,63}(?<!-)(\.(?!-)[a-z0-9-]{1,63}(?<!
|
|
|
48
57
|
*
|
|
49
58
|
* The one test for "is this a host" that an origin read from a stamp and an origin typed on a command line
|
|
50
59
|
* both pass, so the two cannot accept different things.
|
|
60
|
+
*
|
|
61
|
+
* **It answers the same on every runtime, and that is why the punycode rule is stated here.** It used to be
|
|
62
|
+
* borrowed: `seedHostOrigin` asked `new URL` to parse the host and took a throw as the answer, and an invalid
|
|
63
|
+
* A-label like `xn--a.test` was refused because the parser refused it. Node 24.20.0 bumped Ada from 3.4.4 to
|
|
64
|
+
* 4.0.0, Ada 4 stopped rejecting invalid punycode, and the same `pithy seed --host` began succeeding on Node 24
|
|
65
|
+
* while still failing on Node 22 — one command, two answers, decided by the adopter's Node. A rule borrowed from
|
|
66
|
+
* a parser changes under you, so this owns it.
|
|
67
|
+
*
|
|
68
|
+
* **Every A-label is refused, valid or not.** Telling a good one from a bad one is UTS-46, which needs IDNA
|
|
69
|
+
* mapping tables this package is not carrying into a Worker for the sake of a hostname check — and
|
|
70
|
+
* {@link HOSTNAME_PATTERN} is ASCII-only anyway, so a Unicode domain never reached here to begin with. This
|
|
71
|
+
* closes the hand-encoded spelling, and internationalized domains are a feature with a specification behind
|
|
72
|
+
* them rather than a side effect of a parser version.
|
|
51
73
|
*/
|
|
52
74
|
export function isPublicHostname(hostname: string): boolean {
|
|
53
|
-
return hostname.length <= 253 && HOSTNAME_PATTERN.test(hostname);
|
|
75
|
+
return hostname.length <= 253 && HOSTNAME_PATTERN.test(hostname) && !PUNYCODE_LABEL.test(hostname);
|
|
54
76
|
}
|
|
55
77
|
|
|
56
78
|
/** The environments a domain may be declared for — every managed one, never `dev`. */
|
package/src/seed/devLogin.ts
CHANGED
|
@@ -71,3 +71,34 @@ export const DevLogin = z
|
|
|
71
71
|
})
|
|
72
72
|
.describe("A seeded dev login: the signed claim for one seeded user, written to `logs/dev-login.json`.");
|
|
73
73
|
export type DevLogin = z.output<typeof DevLogin>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Every seeded dev login, keyed by `userId` — what `logs/dev-login.json` holds.
|
|
77
|
+
*
|
|
78
|
+
* **One entry per user the seed creates — `#667`.** It used to hold exactly one, named by a per-machine
|
|
79
|
+
* `dev.json`, so being a second seeded user meant reseeding or minting a claim by hand. Both are slow
|
|
80
|
+
* enough that people stop doing it, and the screens only one user can reach stop getting looked at. A
|
|
81
|
+
* claim is a signature over a user id and an expiry, so N of them cost no extra seeded rows and a few
|
|
82
|
+
* hundred bytes each.
|
|
83
|
+
*
|
|
84
|
+
* The key is the `userId`, which each entry also carries: the key is how the record is addressed and the
|
|
85
|
+
* field is what an entry means on its own, once something has picked one out of here.
|
|
86
|
+
*
|
|
87
|
+
* **Order is the file's, and for integer-like ids the language's.** `pithy dev` offers the identities in the
|
|
88
|
+
* order they are read, which is insertion order — except that JS enumerates canonical array-index keys
|
|
89
|
+
* first, in ascending numeric order, so a project whose user ids are stringified integers gets them
|
|
90
|
+
* numerically however the seed wrote them. Nothing depends on the order being the seed's; it is an offer
|
|
91
|
+
* order, not an identity.
|
|
92
|
+
*
|
|
93
|
+
* **The whole file is still one live credential, and the three properties that made one acceptable are
|
|
94
|
+
* what make N acceptable** — `logs/` is gitignored by the starter template, the artifact is written
|
|
95
|
+
* `0600`, and the writer refuses a symlink at the target.
|
|
96
|
+
*
|
|
97
|
+
* **Nothing migrates.** The single-entry file this replaced has strings where an entry belongs, so it does
|
|
98
|
+
* not parse, and every reader already answers "no dev login" to a file that does not — the banner stays
|
|
99
|
+
* quiet until the next `pithy seed`. The artifact is gitignored and regenerated, so that is the plan.
|
|
100
|
+
*/
|
|
101
|
+
export const DevLogins = z
|
|
102
|
+
.record(z.string(), DevLogin)
|
|
103
|
+
.describe("Every seeded dev login, keyed by user id, as `logs/dev-login.json` holds them.");
|
|
104
|
+
export type DevLogins = z.output<typeof DevLogins>;
|
package/src/version.generated.ts
CHANGED