@rexezuge/runtime 1.0.0 → 1.0.2
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
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @rexezuge/runtime
|
|
2
|
+
|
|
3
|
+
DI container, configuration, worker bases, logger, and KV cache for Cloudflare Workers.
|
|
4
|
+
|
|
5
|
+
Zero dependencies (the one platform import is type-only, resolved through each consumer's generated wrangler types).
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @rexezuge/runtime
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. DI — `Container` / `Token` / `RequestScope`
|
|
14
|
+
|
|
15
|
+
Minimal by design: factory + singleton scopes, branded tokens for inference, nothing else.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { Container, type Token } from '@rexezuge/runtime';
|
|
19
|
+
|
|
20
|
+
interface Mailer { send(to: string): Promise<void> }
|
|
21
|
+
const MailerToken: Token<Mailer> = 'Mailer';
|
|
22
|
+
|
|
23
|
+
const root = new Container().bindValue(MailerToken, new SmtpMailer());
|
|
24
|
+
const mailer = root.get(MailerToken); // Mailer, no explicit generic needed
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Composition roots wire implementations once; request handlers resolve via `asScopedContext` / `getRequestScope` rather than passing a container through business logic.
|
|
28
|
+
|
|
29
|
+
## 2. Config — `AppConfiguration` / `EnvParser`
|
|
30
|
+
|
|
31
|
+
Consumers subclass `AppConfiguration` and compose their own typed sections (limits, auth, replication), each reading env once through `EnvParser`:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { AppConfiguration, EnvParser } from '@rexezuge/runtime';
|
|
35
|
+
|
|
36
|
+
class MyConfig extends AppConfiguration {
|
|
37
|
+
public getPageSize(): number {
|
|
38
|
+
return EnvParser.number(this.raw(), 'PAGE_SIZE', 50);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const config = MyConfig.fromEnv(env);
|
|
43
|
+
for (const warning of config.validate()) console.warn(warning); // warnings, never throws
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`getSiteUrl()` strips trailing slashes so callers can concatenate paths. `validate()` returns startup warnings (e.g. `DEMO_MODE` in production) instead of throwing a 500 on a request path.
|
|
47
|
+
|
|
48
|
+
## 3. Worker bases
|
|
49
|
+
|
|
50
|
+
| Base | Extends for |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `AbstractEntrypointWorker` | HTTP + cron entrypoints (`onRequest` / `onScheduled`) |
|
|
53
|
+
| `AbstractDurableObjectWorker` | Durable Object workers |
|
|
54
|
+
| `AbstractQueueWorker` | Queue consumers |
|
|
55
|
+
| `AbstractWorkflowWorker` | Workflows |
|
|
56
|
+
|
|
57
|
+
`fetch()` / `scheduled()` log-and-contain: an unhandled throw is a 500 response or a logged cron failure, never a platform crash. There is deliberately no `/__scheduled` HTTP branch — cron runs through the wrangler `triggers.crons` binding. The structural `WorkerExecutionContext` / `WorkerScheduledController` types mean this package typechecks without `@cloudflare/workers-types`.
|
|
58
|
+
|
|
59
|
+
## 4. Logger and KV cache
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { createLogger, KvCache } from '@rexezuge/runtime';
|
|
63
|
+
|
|
64
|
+
const logger = createLogger('Sync', 'my-repo', env); // level from env.LOG_LEVEL ?? process.env, defaults to info
|
|
65
|
+
logger.info('starting sync');
|
|
66
|
+
|
|
67
|
+
const cache = new KvCache(env.CACHE); // fail-soft: reads null, writes false, D1/DO stay authoritative
|
|
68
|
+
await cache.putText('session', 'sess:abc', 'payload', { ttlSeconds: 300 });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`KV_DOMAINS` / `buildKvKey` / `clampTtl` keep every repo's key shapes and TTL ceilings identical.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Verifying this package
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pnpm --filter @rexezuge/runtime exec tsc -p tsconfig.json
|
|
79
|
+
pnpm --filter @rexezuge/runtime typecheck
|
|
80
|
+
pnpm --filter @rexezuge/runtime test
|
|
81
|
+
```
|
|
@@ -22,6 +22,15 @@ declare class EnvParser {
|
|
|
22
22
|
*/
|
|
23
23
|
static isValidPositiveInt(env: unknown, key: string): boolean;
|
|
24
24
|
static string(env: unknown, key: string, defaultValue: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* A non-negative integer, zero included.
|
|
27
|
+
*
|
|
28
|
+
* Distinct from `positiveInt` because zero is a meaningful configuration for
|
|
29
|
+
* retention and quota knobs ("keep nothing"), and a parser that rejected it
|
|
30
|
+
* would silently substitute the default — so setting `0` in the dashboard
|
|
31
|
+
* would appear to do nothing at all.
|
|
32
|
+
*/
|
|
33
|
+
static nonNegativeInt(env: unknown, key: string, defaultValue: string): number;
|
|
25
34
|
static boolean(env: unknown, key: string, defaultValue: string): boolean;
|
|
26
35
|
/** The raw value, or undefined when unset. Public because presence checks (validate) need it. */
|
|
27
36
|
static readString(env: unknown, key: string): string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvParser.d.ts","sourceRoot":"","sources":["../../src/config/EnvParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,cAAM,SAAS;WACC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAMlF;;;;;;;OAOG;WACW,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;WAOtD,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"EnvParser.d.ts","sourceRoot":"","sources":["../../src/config/EnvParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,cAAM,SAAS;WACC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAMlF;;;;;;;OAOG;WACW,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;WAOtD,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAI7E;;;;;;;OAOG;WACW,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;WAMvE,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAI/E,iGAAiG;WACnF,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAGxE;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/config/EnvParser.js
CHANGED
|
@@ -34,6 +34,19 @@ class EnvParser {
|
|
|
34
34
|
static string(env, key, defaultValue) {
|
|
35
35
|
return this.readString(env, key) ?? defaultValue;
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* A non-negative integer, zero included.
|
|
39
|
+
*
|
|
40
|
+
* Distinct from `positiveInt` because zero is a meaningful configuration for
|
|
41
|
+
* retention and quota knobs ("keep nothing"), and a parser that rejected it
|
|
42
|
+
* would silently substitute the default — so setting `0` in the dashboard
|
|
43
|
+
* would appear to do nothing at all.
|
|
44
|
+
*/
|
|
45
|
+
static nonNegativeInt(env, key, defaultValue) {
|
|
46
|
+
const value = this.readString(env, key);
|
|
47
|
+
const parsed = Number(value ?? defaultValue);
|
|
48
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : Number(defaultValue);
|
|
49
|
+
}
|
|
37
50
|
static boolean(env, key, defaultValue) {
|
|
38
51
|
return (this.readString(env, key) ?? defaultValue) === 'true';
|
|
39
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvParser.js","sourceRoot":"","sources":["../../src/config/EnvParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,SAAS;IACN,MAAM,CAAC,WAAW,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,kBAAkB,CAAC,GAAY,EAAE,GAAW;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IACpD,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAClE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC;IACnD,CAAC;IAEM,MAAM,CAAC,OAAO,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACnE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,MAAM,CAAC;IAChE,CAAC;IAED,iGAAiG;IAC1F,MAAM,CAAC,UAAU,CAAC,GAAY,EAAE,GAAW;QAChD,OAAQ,GAA0C,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"EnvParser.js","sourceRoot":"","sources":["../../src/config/EnvParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,SAAS;IACN,MAAM,CAAC,WAAW,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACpF,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,kBAAkB,CAAC,GAAY,EAAE,GAAW;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IACpD,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAClE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC;IACnD,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,cAAc,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACrF,CAAC;IAEM,MAAM,CAAC,OAAO,CAAC,GAAY,EAAE,GAAW,EAAE,YAAoB;QACnE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,MAAM,CAAC;IAChE,CAAC;IAED,iGAAiG;IAC1F,MAAM,CAAC,UAAU,CAAC,GAAY,EAAE,GAAW;QAChD,OAAQ,GAA0C,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rexezuge/runtime",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"typescript": "6.0.3",
|
|
30
30
|
"vitest": "4.1.11"
|
|
31
31
|
},
|
|
32
|
+
"description": "DI container, configuration, worker bases, logger, and KV cache for Cloudflare Workers.",
|
|
32
33
|
"scripts": {
|
|
33
34
|
"build": "tsc -p tsconfig.json",
|
|
34
35
|
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|