pipework 0.202.0 → 0.203.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/CHANGELOG.md +4 -0
- package/REFERENCE.md +4 -0
- package/dist/REFERENCE.md +13 -322
- package/dist/data/db/advisory-lock.d.ts +6 -0
- package/dist/data/db/advisory-lock.d.ts.map +1 -1
- package/dist/data/db/advisory-lock.js +23 -16
- package/dist/data/db/advisory-lock.js.map +1 -1
- package/dist/data/db/namespace.d.ts +3 -1
- package/dist/data/db/namespace.d.ts.map +1 -1
- package/dist/data/db/namespace.js +3 -1
- package/dist/data/db/namespace.js.map +1 -1
- package/dist/infra/email/sigv4.d.ts +24 -0
- package/dist/infra/email/sigv4.d.ts.map +1 -0
- package/dist/infra/email/sigv4.js +55 -0
- package/dist/infra/email/sigv4.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.203.0
|
|
4
|
+
|
|
5
|
+
- **Added: `pipe.tryAdvisoryLock`** (#775). The non-blocking form of `pipe.advisoryLock`: `pg_try_advisory_xact_lock` with the same three key forms and the same hashing, returning `true` if the lock was won and `false` at once if another transaction holds it. A lock won is held until commit or rollback, and `advisoryLock` and `tryAdvisoryLock` on the same arguments contend on the same lock.
|
|
6
|
+
|
|
3
7
|
## 0.202.0
|
|
4
8
|
|
|
5
9
|
- **Added: `assign` on `alerts.clientFaults` and `alerts.requestFaults`** (#773). `assign(report)` (or `assign(fault)`) may return `{ owner?, runbook? }` to choose who gets that one alert. A field it leaves undefined keeps the app's (or the hook's) value. A request report whose refusal the server caused can now go to the server's owner, not the page's. For `clientFaults`, an `assign` that throws is handled the way a throwing `key` is: it is logged and recorded as a fault, nothing is raised, and the answer is still 204.
|
package/REFERENCE.md
CHANGED
|
@@ -865,6 +865,10 @@ Returns excluded-column references for onConflictDoUpdate set clauses.
|
|
|
865
865
|
|
|
866
866
|
Acquires a transaction-scoped advisory lock. Released at commit/rollback.
|
|
867
867
|
|
|
868
|
+
### `pipe.tryAdvisoryLock`
|
|
869
|
+
|
|
870
|
+
Non-blocking advisoryLock: true if the transaction-scoped lock was won, false if another transaction holds it.
|
|
871
|
+
|
|
868
872
|
### `pipe.serializable`
|
|
869
873
|
|
|
870
874
|
Runs a function in a SERIALIZABLE transaction with automatic retry on serialization failures and deadlocks.
|
package/dist/REFERENCE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Pipework API Reference
|
|
2
2
|
|
|
3
3
|
> Auto-generated from source JSDoc. Do not edit manually.
|
|
4
|
-
> Generated: 2026-10-
|
|
4
|
+
> Generated: 2026-10-09
|
|
5
5
|
|
|
6
6
|
## Contents
|
|
7
7
|
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
- [jobs — Background Jobs](#jobs-background-jobs)
|
|
11
11
|
- [pipeline — Multi-Step Pipelines](#pipeline-multi-step-pipelines)
|
|
12
12
|
- [state — State Machines](#state-state-machines)
|
|
13
|
-
- [steps](#steps)
|
|
14
13
|
- [auth — Authentication](#auth-authentication)
|
|
15
14
|
- [rbac — Access Control](#rbac-access-control)
|
|
16
15
|
- [tenant — Multi-Tenancy](#tenant-multi-tenancy)
|
|
@@ -31,9 +30,7 @@
|
|
|
31
30
|
- [cache — Caching](#cache-caching)
|
|
32
31
|
- [credits](#credits)
|
|
33
32
|
- [mail](#mail)
|
|
34
|
-
- [untrustedFetch](#untrustedfetch)
|
|
35
33
|
- [storage](#storage)
|
|
36
|
-
- [support](#support)
|
|
37
34
|
- [webhook — Inbound & Outbound Webhooks](#webhook-inbound-outbound-webhooks)
|
|
38
35
|
- [behavior — Resource Decorators](#behavior-resource-decorators)
|
|
39
36
|
- [fitting — Dependency Injection](#fitting-dependency-injection)
|
|
@@ -88,18 +85,6 @@ function createManifold<const TEnv extends EnvDefs = EnvDefs>( raw: Omit<Bluepri
|
|
|
88
85
|
interface Manifold<TEnv extends EnvDefs = EnvDefs>
|
|
89
86
|
```
|
|
90
87
|
|
|
91
|
-
**`ScriptOptions`** — Options for {@link Manifold.script}.
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
interface ScriptOptions
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**`StartOptions`** — Options for {@link Manifold.start}.
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
interface StartOptions
|
|
101
|
-
```
|
|
102
|
-
|
|
103
88
|
**`SeedOptions`** — ALS context the {@link Manifold.seed} callback runs under — tenant scope, auth principal, and job type.
|
|
104
89
|
|
|
105
90
|
```typescript
|
|
@@ -244,14 +229,6 @@ Creates a job queue with claim/complete/fail lifecycle, heartbeat, and dead lett
|
|
|
244
229
|
|
|
245
230
|
Executes a fitting handler as a background job with its own Flow context.
|
|
246
231
|
|
|
247
|
-
### `jobs.later`
|
|
248
|
-
|
|
249
|
-
The error to throw to end an attempt as "later": pending again after `delayMs`, no attempt counted.
|
|
250
|
-
|
|
251
|
-
### `jobs.permanent`
|
|
252
|
-
|
|
253
|
-
The error to throw to dead-letter the job now, whatever attempts remain.
|
|
254
|
-
|
|
255
232
|
### `jobs.parseCron`
|
|
256
233
|
|
|
257
234
|
Parses a 5-field cron expression into a CronSchedule (minute, hour, dom, month, dow).
|
|
@@ -292,14 +269,6 @@ Thrown when a transition is not allowed from the current state.
|
|
|
292
269
|
|
|
293
270
|
Thrown when the state machine definition is internally inconsistent.
|
|
294
271
|
|
|
295
|
-
## steps
|
|
296
|
-
|
|
297
|
-
Step graphs over a job queue: results recorded by their inputs, only missing steps run.
|
|
298
|
-
|
|
299
|
-
### `steps.define`
|
|
300
|
-
|
|
301
|
-
Defines a graph of named steps over a jobs Queue. Pass it to `createWorkerSurface({ graphs })` to run its steps.
|
|
302
|
-
|
|
303
272
|
## auth — Authentication
|
|
304
273
|
|
|
305
274
|
Authentication namespace — session management, multi-org support, auth chain resolution.
|
|
@@ -320,10 +289,6 @@ Hashes and verifies passwords with scrypt; reports when a stored hash needs reha
|
|
|
320
289
|
|
|
321
290
|
Guarded password sign-in that slows, then refuses, repeated failures per account and per client.
|
|
322
291
|
|
|
323
|
-
### `auth.emailLinks`
|
|
324
|
-
|
|
325
|
-
Emailed single-use links that prove control of an address: password reset and address verification; the token is never stored.
|
|
326
|
-
|
|
327
292
|
### `auth.runChain`
|
|
328
293
|
|
|
329
294
|
Executes an auth chain (strategy pipeline) to resolve auth + tenant from a request.
|
|
@@ -358,7 +323,7 @@ interface AuthContext
|
|
|
358
323
|
interface AuthStrategy<TAuth>
|
|
359
324
|
```
|
|
360
325
|
|
|
361
|
-
**`AuthRequest`** — Normalized request shape passed to auth strategies — headers,
|
|
326
|
+
**`AuthRequest`** — Normalized request shape passed to auth strategies — headers, cookies, method, url.
|
|
362
327
|
|
|
363
328
|
```typescript
|
|
364
329
|
interface AuthRequest
|
|
@@ -388,18 +353,6 @@ interface TenantResolver<TAuth>
|
|
|
388
353
|
interface AuthChainConfig<TAuth>
|
|
389
354
|
```
|
|
390
355
|
|
|
391
|
-
**`SessionAuth`** — What `sessions.strategy()` authenticates: the token's user and org, its roles, and where the token came from.
|
|
392
|
-
|
|
393
|
-
```typescript
|
|
394
|
-
type SessionAuth = BaseAuth &
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
**`SessionStrategyOptions`** — Options for `sessions.strategy()`.
|
|
398
|
-
|
|
399
|
-
```typescript
|
|
400
|
-
interface SessionStrategyOptions
|
|
401
|
-
```
|
|
402
|
-
|
|
403
356
|
**`SessionConfig`** — Session configuration — signing keys, issuer, audience, token TTLs, refresh rotation.
|
|
404
357
|
|
|
405
358
|
```typescript
|
|
@@ -671,10 +624,6 @@ Base error class with code, statusCode, and suggestion fields.
|
|
|
671
624
|
|
|
672
625
|
403 — authenticated but insufficient permissions.
|
|
673
626
|
|
|
674
|
-
### `errors.CrossSiteRequest`
|
|
675
|
-
|
|
676
|
-
403 `CROSS_SITE_REQUEST` — a cookie-authenticated write that did not come from the app's own site.
|
|
677
|
-
|
|
678
627
|
### `errors.Validation`
|
|
679
628
|
|
|
680
629
|
422 — input validation failed, carries field-level details.
|
|
@@ -695,17 +644,13 @@ Base error class with code, statusCode, and suggestion fields.
|
|
|
695
644
|
|
|
696
645
|
415 — request body media type not accepted by the route.
|
|
697
646
|
|
|
698
|
-
### `errors.MalformedMultipart`
|
|
699
|
-
|
|
700
|
-
400 `MALFORMED_MULTIPART` — a multipart body that cannot be parsed or ends before its closing boundary.
|
|
701
|
-
|
|
702
647
|
## lifecycle — Startup & Shutdown
|
|
703
648
|
|
|
704
649
|
Application lifecycle namespace — startup orchestration with hooks and timeouts.
|
|
705
650
|
|
|
706
651
|
### `lifecycle.orchestrate`
|
|
707
652
|
|
|
708
|
-
Runs pre-start hooks (DB readiness checks, migrations, etc.) with a configurable timeout.
|
|
653
|
+
Runs pre-start hooks (DB readiness checks, migrations, etc.) with a configurable timeout.
|
|
709
654
|
|
|
710
655
|
## log — Structured Logging
|
|
711
656
|
|
|
@@ -745,7 +690,7 @@ Creates a worker surface — a long-running process that claims and executes job
|
|
|
745
690
|
|
|
746
691
|
### `surface.script`
|
|
747
692
|
|
|
748
|
-
Creates a script surface — a one-shot process that runs and exits (migrations, seeds, CLI tools).
|
|
693
|
+
Creates a script surface — a one-shot process that runs and exits (migrations, seeds, CLI tools).
|
|
749
694
|
|
|
750
695
|
## pipe — Database
|
|
751
696
|
|
|
@@ -816,10 +761,6 @@ Acquires a transaction-scoped advisory lock. Released at commit/rollback.
|
|
|
816
761
|
|
|
817
762
|
Runs a function in a SERIALIZABLE transaction with automatic retry on serialization failures and deadlocks.
|
|
818
763
|
|
|
819
|
-
### `pipe.withTimeouts`
|
|
820
|
-
|
|
821
|
-
Sets statement_timeout and/or lock_timeout for the current transaction in one statement, then runs fn; a statement cancelled for them rejects with StatementTimeoutError or LockTimeoutError.
|
|
822
|
-
|
|
823
764
|
### `pipe.bulkSet`
|
|
824
765
|
|
|
825
766
|
Bulk UPDATE ... FROM (VALUES ...) — updates multiple rows with per-row values in a single statement.
|
|
@@ -828,10 +769,6 @@ Bulk UPDATE ... FROM (VALUES ...) — updates multiple rows with per-row values
|
|
|
828
769
|
|
|
829
770
|
Produces a typed VALUES clause for bulk operations — the base primitive for bulkSet and bulkUpsert.
|
|
830
771
|
|
|
831
|
-
### `pipe.fn`
|
|
832
|
-
|
|
833
|
-
A set-returning SQL function as a typed source for `.from()` and joins — `pipe.fn('schema.f', { args: [field.uuid()], columns: { path: field.text() } })`. Arguments are bound and cast to their declared types.
|
|
834
|
-
|
|
835
772
|
### `pipe.field`
|
|
836
773
|
|
|
837
774
|
Field builders for domain definitions — uuid(), text(), integer(), etc.
|
|
@@ -844,17 +781,13 @@ Registers a domain definition with table, validators, and factory projections. T
|
|
|
844
781
|
|
|
845
782
|
Returns the global registry of all domain definitions.
|
|
846
783
|
|
|
847
|
-
### `pipe.external`
|
|
848
|
-
|
|
849
|
-
Declares a table or view another service owns (`pipe.external(name, fields, { schema, table? })`): typed columns and every query operator, read-only, never migrated, not tenant-scoped.
|
|
850
|
-
|
|
851
784
|
### `pipe.update`
|
|
852
785
|
|
|
853
786
|
Pipework-owned UPDATE builder — the only consumer-facing way to update pipework-managed tables (Q8).
|
|
854
787
|
|
|
855
788
|
### `pipe.insert`
|
|
856
789
|
|
|
857
|
-
Pipework-owned INSERT builder — the only consumer-facing way to insert into pipework-managed tables (Q8).
|
|
790
|
+
Pipework-owned INSERT builder — the only consumer-facing way to insert into pipework-managed tables (Q8).
|
|
858
791
|
|
|
859
792
|
### `pipe.delete`
|
|
860
793
|
|
|
@@ -862,7 +795,7 @@ Pipework-owned DELETE builder — the only consumer-facing way to delete from pi
|
|
|
862
795
|
|
|
863
796
|
### `pipe.upsert`
|
|
864
797
|
|
|
865
|
-
Pipework-owned UPSERT builder — insert with conflict resolution (Q8).
|
|
798
|
+
Pipework-owned UPSERT builder — insert with conflict resolution (Q8).
|
|
866
799
|
|
|
867
800
|
### Types
|
|
868
801
|
|
|
@@ -878,54 +811,12 @@ interface WindowSpec
|
|
|
878
811
|
interface ValueColumnDef
|
|
879
812
|
```
|
|
880
813
|
|
|
881
|
-
**`JsonbElements`** — A jsonb array read as its elements' text. Produced by {@link jsonbElements}.
|
|
882
|
-
|
|
883
|
-
```typescript
|
|
884
|
-
interface JsonbElements
|
|
885
|
-
```
|
|
886
|
-
|
|
887
|
-
**`ArraySource`** — Something whose elements `arrayAny` / `arrayAll` can test.
|
|
888
|
-
|
|
889
|
-
```typescript
|
|
890
|
-
type ArraySource =
|
|
891
|
-
```
|
|
892
|
-
|
|
893
|
-
**`ElementOf`** — The element type of an {@link ArraySource}.
|
|
894
|
-
|
|
895
|
-
```typescript
|
|
896
|
-
type ElementOf<S> =
|
|
897
|
-
```
|
|
898
|
-
|
|
899
|
-
**`FunctionSpec`** — Declares a SQL function's argument and result-column shapes. See {@link fn}.
|
|
900
|
-
|
|
901
|
-
```typescript
|
|
902
|
-
interface FunctionSpec<TArgs extends readonly AnyField[], TColumns extends Record<string, AnyField>>
|
|
903
|
-
```
|
|
904
|
-
|
|
905
|
-
**`FunctionSourceFields`** — The selected fields of a function source: each result column as a typed SQL expression.
|
|
906
|
-
|
|
907
|
-
```typescript
|
|
908
|
-
type FunctionSourceFields<TColumns extends Record<string, AnyField>> =
|
|
909
|
-
```
|
|
910
|
-
|
|
911
|
-
**`FunctionSource`** — A function call usable in `.from()` and joins; its result columns are properties of it.
|
|
912
|
-
|
|
913
|
-
```typescript
|
|
914
|
-
type FunctionSource<TAlias extends string, TColumns extends Record<string, AnyField>> =
|
|
915
|
-
```
|
|
916
|
-
|
|
917
814
|
**`SerializableOptions`** — Retry policy for {@link serializable}: how many attempts on a serialization failure / deadlock, and the base backoff between them.
|
|
918
815
|
|
|
919
816
|
```typescript
|
|
920
817
|
interface SerializableOptions
|
|
921
818
|
```
|
|
922
819
|
|
|
923
|
-
**`TimeoutOptions`** — Which timeouts {@link withTimeouts} sets; each a positive integer number of milliseconds.
|
|
924
|
-
|
|
925
|
-
```typescript
|
|
926
|
-
interface TimeoutOptions
|
|
927
|
-
```
|
|
928
|
-
|
|
929
820
|
**`ManagedConnection`** — A standalone pooled connection: the raw postgres.js client, its drizzle handle, and a `close()` that ends the pool.
|
|
930
821
|
|
|
931
822
|
```typescript
|
|
@@ -946,10 +837,6 @@ JSONB query operators — typed helpers for PostgreSQL JSONB containment, key ch
|
|
|
946
837
|
|
|
947
838
|
The @> containment operator — tests whether a JSONB column contains the given value.
|
|
948
839
|
|
|
949
|
-
### `jsonb.merge`
|
|
950
|
-
|
|
951
|
-
Merges an object into a JSONB column in `.set()`: `coalesce(col, '{}') || value`. Top-level keys overwrite; others are kept.
|
|
952
|
-
|
|
953
840
|
### `jsonb.containedBy`
|
|
954
841
|
|
|
955
842
|
The <@ contained-by operator — tests whether a JSONB column is contained by the given value.
|
|
@@ -1016,60 +903,6 @@ type Schema<T = unknown> = z.ZodType<T>
|
|
|
1016
903
|
type Infer<T extends Schema> = z.infer<T>
|
|
1017
904
|
```
|
|
1018
905
|
|
|
1019
|
-
**`StringSchema`** — A string validator — what check.string() returns, nameable without importing zod.
|
|
1020
|
-
|
|
1021
|
-
```typescript
|
|
1022
|
-
interface StringSchema extends z.ZodString
|
|
1023
|
-
```
|
|
1024
|
-
|
|
1025
|
-
**`NumberSchema`** — A number validator — what check.number() returns.
|
|
1026
|
-
|
|
1027
|
-
```typescript
|
|
1028
|
-
interface NumberSchema extends z.ZodNumber
|
|
1029
|
-
```
|
|
1030
|
-
|
|
1031
|
-
**`BooleanSchema`** — A boolean validator — what check.boolean() returns.
|
|
1032
|
-
|
|
1033
|
-
```typescript
|
|
1034
|
-
interface BooleanSchema extends z.ZodBoolean
|
|
1035
|
-
```
|
|
1036
|
-
|
|
1037
|
-
**`EnumSchema`** — An enum validator over string literals — what check.enum([...]) returns.
|
|
1038
|
-
|
|
1039
|
-
```typescript
|
|
1040
|
-
interface EnumSchema<V extends string = string> extends z.ZodEnum<
|
|
1041
|
-
```
|
|
1042
|
-
|
|
1043
|
-
**`LiteralSchema`** — A literal validator — what check.literal(v) returns.
|
|
1044
|
-
|
|
1045
|
-
```typescript
|
|
1046
|
-
interface LiteralSchema<V extends string | number | boolean | null = string> extends z.ZodLiteral<V>
|
|
1047
|
-
```
|
|
1048
|
-
|
|
1049
|
-
**`ArraySchema`** — An array validator — what check.array(item) returns.
|
|
1050
|
-
|
|
1051
|
-
```typescript
|
|
1052
|
-
interface ArraySchema<Item extends z.core.SomeType = z.core.SomeType> extends z.ZodArray<Item>
|
|
1053
|
-
```
|
|
1054
|
-
|
|
1055
|
-
**`OptionalSchema`** — An optional validator — what check.optional(inner) returns.
|
|
1056
|
-
|
|
1057
|
-
```typescript
|
|
1058
|
-
interface OptionalSchema<Inner extends z.core.SomeType = z.core.SomeType> extends z.ZodOptional<Inner>
|
|
1059
|
-
```
|
|
1060
|
-
|
|
1061
|
-
**`NullableSchema`** — A nullable validator — what check.nullable(inner) returns.
|
|
1062
|
-
|
|
1063
|
-
```typescript
|
|
1064
|
-
interface NullableSchema<Inner extends z.core.SomeType = z.core.SomeType> extends z.ZodNullable<Inner>
|
|
1065
|
-
```
|
|
1066
|
-
|
|
1067
|
-
**`ObjectSchema`** — An object validator whose .extend, .pick, .omit and .partial results stay ObjectSchema — what check.object({...}) returns.
|
|
1068
|
-
|
|
1069
|
-
```typescript
|
|
1070
|
-
type ObjectSchema<S extends Shape = Shape> =
|
|
1071
|
-
```
|
|
1072
|
-
|
|
1073
906
|
## temporal — Bitemporal Data
|
|
1074
907
|
|
|
1075
908
|
Temporal (bitemporal) data namespace — version history with effective date ranges.
|
|
@@ -1114,14 +947,6 @@ Query all versions of temporal records (no date filter).
|
|
|
1114
947
|
|
|
1115
948
|
Close the current version and create a new one with updated data.
|
|
1116
949
|
|
|
1117
|
-
### `temporal.setVersion`
|
|
1118
|
-
|
|
1119
|
-
Append the next version of an append-only-versions definition: serialised per scope, numbered, never back-dated, audited.
|
|
1120
|
-
|
|
1121
|
-
### `temporal.versionAt`
|
|
1122
|
-
|
|
1123
|
-
The version in force at a moment: the row with the greatest effectiveFrom at or before it.
|
|
1124
|
-
|
|
1125
950
|
## valve
|
|
1126
951
|
|
|
1127
952
|
Valve namespace — typed, directional, gated boundaries between code silos.
|
|
@@ -1304,18 +1129,6 @@ Alerts namespace — raise and resolve keyed conditions, grouped, delivered to s
|
|
|
1304
1129
|
|
|
1305
1130
|
Creates an alerts handle.
|
|
1306
1131
|
|
|
1307
|
-
### `alerts.http`
|
|
1308
|
-
|
|
1309
|
-
Routes for an operations agent: list, get, totals, delivery health, acknowledge, resolve, link; bearer credentials.
|
|
1310
|
-
|
|
1311
|
-
### `alerts.clientFaults`
|
|
1312
|
-
|
|
1313
|
-
One POST route that records failures reported by browser code as a trace step and an alert; answers 204, no session needed. Send with `reportClientFault` from `pipework/client`.
|
|
1314
|
-
|
|
1315
|
-
### `alerts.requestFaults`
|
|
1316
|
-
|
|
1317
|
-
An `onInternalError` hook for the HTTP server: raises `request-fault:<METHOD> <route>` for each internal 500.
|
|
1318
|
-
|
|
1319
1132
|
### `alerts.webhook`
|
|
1320
1133
|
|
|
1321
1134
|
A sink that POSTs the alert as signed JSON to a URL.
|
|
@@ -1348,10 +1161,6 @@ The newest record's `{ seq, hash }` in the tenant's audit hash chain (blueprint
|
|
|
1348
1161
|
|
|
1349
1162
|
Walks the tenant's audit hash chain and reports the first break (hash-mismatch, prev-mismatch, missing, head-mismatch, anchor-mismatch), or `{ ok: true }`.
|
|
1350
1163
|
|
|
1351
|
-
### `audit.removeTenant`
|
|
1352
|
-
|
|
1353
|
-
Deletes every audit record of one tenant and its hash chain, for the closure of that tenant's account. Irreversible; returns the number of records removed. Other tenants' records and chains are untouched.
|
|
1354
|
-
|
|
1355
1164
|
## cache — Caching
|
|
1356
1165
|
|
|
1357
1166
|
In-memory caching namespace — TTL-based with stats, preload, and tenant-aware variants.
|
|
@@ -1404,36 +1213,6 @@ Inbound source: SES receipt rule storing raw messages in S3 and notifying a sign
|
|
|
1404
1213
|
|
|
1405
1214
|
Inbound development source: `.eml` files dropped in a folder, received by `scan()`; refused in production.
|
|
1406
1215
|
|
|
1407
|
-
## untrustedFetch
|
|
1408
|
-
|
|
1409
|
-
Untrusted fetch — fetch one URL a stranger gave without letting them reach the app's private network.
|
|
1410
|
-
|
|
1411
|
-
### `untrustedFetch.get`
|
|
1412
|
-
|
|
1413
|
-
Fetches `url` with GET and returns `{ ok: true, url, status, contentType, body, bytes }`, or `{ ok: false, reason, message }`
|
|
1414
|
-
naming the rule that refused: `scheme`, `address`, `redirects`, `too_large`, `timeout`, `status`, `rejected` or `network`.
|
|
1415
|
-
It does not throw for these.
|
|
1416
|
-
|
|
1417
|
-
Rules, none of which can be switched off: only `http:` and `https:`; the name is resolved and every address is checked
|
|
1418
|
-
(loopback, private, link-local including cloud metadata, CGNAT, unique-local and site-local IPv6, multicast, reserved,
|
|
1419
|
-
unspecified, and IPv4-mapped or NAT64 forms of these; literal IP URLs likewise) and the connection goes to a checked
|
|
1420
|
-
address; redirects are followed up to `maxRedirects` and each hop is checked as the first, and the app's `headers` go only to the first origin;
|
|
1421
|
-
the body is stopped the moment it passes `maxBytes`, whatever Content-Length says; `timeoutMs` covers the whole fetch.
|
|
1422
|
-
`accept({ status, contentType, firstBytes })` sees the first 1024 bytes before the body is kept: return false, or a string
|
|
1423
|
-
(your own message), to refuse with `rejected`. Messages never contain an address or anything a server sent.
|
|
1424
|
-
|
|
1425
|
-
`resolve` and `connect` are for tests: `resolve(hostname)` replaces DNS and `connect(target)` replaces the socket after the
|
|
1426
|
-
address check passed, so a test sends a fake public address to a local server. The address check always runs on what `resolve` returns.
|
|
1427
|
-
|
|
1428
|
-
The call is the trace step `pipework/fetch:get`; its child `pipework/fetch:outcome` carries host, status, bytes and reason.
|
|
1429
|
-
The full URL is recorded only when `urlIsSafeToTrace` is true; otherwise only the host.
|
|
1430
|
-
|
|
1431
|
-
```ts
|
|
1432
|
-
const got = await untrustedFetch.get(pasted, { maxBytes: 5_000_000, timeoutMs: 10_000, maxRedirects: 3,
|
|
1433
|
-
accept: h => h.firstBytes[0] === 0x25 || 'That does not look like a PDF.' })
|
|
1434
|
-
if (!got.ok) return tell(got.message)
|
|
1435
|
-
```
|
|
1436
|
-
|
|
1437
1216
|
## storage
|
|
1438
1217
|
|
|
1439
1218
|
Storage namespace — tenant-scoped, content-addressed file storage with signed URLs and retention.
|
|
@@ -1450,18 +1229,6 @@ S3-compatible backend (AWS S3, MinIO, R2): SigV4 over `fetch`, multipart streami
|
|
|
1450
1229
|
|
|
1451
1230
|
Local-disk backend for development and tests; refused in production.
|
|
1452
1231
|
|
|
1453
|
-
## support
|
|
1454
|
-
|
|
1455
|
-
Support namespace — tickets from email (and later chat), with replies sent only after an approval.
|
|
1456
|
-
|
|
1457
|
-
### `support.create`
|
|
1458
|
-
|
|
1459
|
-
Creates the support handle: tickets, messages, notes, links, drafts, `approve`, `receiveEmail`, and the events job.
|
|
1460
|
-
|
|
1461
|
-
### `support.templates`
|
|
1462
|
-
|
|
1463
|
-
The reply template to spread into `mail.create({ templates })`; it renders the approved draft verbatim.
|
|
1464
|
-
|
|
1465
1232
|
## webhook — Inbound & Outbound Webhooks
|
|
1466
1233
|
|
|
1467
1234
|
Webhook namespace — inbound verification, outbound delivery with retries, HMAC signing.
|
|
@@ -1552,10 +1319,6 @@ Returns the current Flow or undefined — use for optional context detection.
|
|
|
1552
1319
|
|
|
1553
1320
|
Creates a Flow for test isolation with optional auth and tenant overrides.
|
|
1554
1321
|
|
|
1555
|
-
### `flow.actAs`
|
|
1556
|
-
|
|
1557
|
-
Runs `fn` as a tenant and user chosen inside a tenantless Flow (sign-up, a public sign-in): RLS, audit and trace under that tenant, on the request's transaction.
|
|
1558
|
-
|
|
1559
1322
|
## http — Server
|
|
1560
1323
|
|
|
1561
1324
|
HTTP namespace: `http.file()` builds a file response; the server itself is managed by manifold.start().
|
|
@@ -1580,40 +1343,6 @@ interface SecurityConfig
|
|
|
1580
1343
|
interface RateLimitConfig
|
|
1581
1344
|
```
|
|
1582
1345
|
|
|
1583
|
-
**`RateLimitWindow`** — One fixed window: at most `max` requests per `windowSeconds`.
|
|
1584
|
-
|
|
1585
|
-
```typescript
|
|
1586
|
-
interface RateLimitWindow
|
|
1587
|
-
```
|
|
1588
|
-
|
|
1589
|
-
**`RateLimitClass`**
|
|
1590
|
-
|
|
1591
|
-
A named limit class: any of a per-user, per-tenant, per-address and total window, each counted on its own.
|
|
1592
|
-
Each key takes one window or an array of windows (distinct `windowSeconds`); a request is counted against
|
|
1593
|
-
all of a key's windows and refused if any is over.
|
|
1594
|
-
|
|
1595
|
-
```typescript
|
|
1596
|
-
interface RateLimitClass
|
|
1597
|
-
```
|
|
1598
|
-
|
|
1599
|
-
**`RateLimitRefusal`** — What `onRefused` is told about one refused window of one request.
|
|
1600
|
-
|
|
1601
|
-
```typescript
|
|
1602
|
-
interface RateLimitRefusal
|
|
1603
|
-
```
|
|
1604
|
-
|
|
1605
|
-
**`RateLimitClassesConfig`**
|
|
1606
|
-
|
|
1607
|
-
Named limit classes, checked after auth and counted in Postgres (`pipework_rate_limit_counts`, opted in
|
|
1608
|
-
with the blueprint's `rateLimits: {}`), so every server process on the same database shares one count.
|
|
1609
|
-
Keys are counted perUser, perTenant, perAddress, total in turn, up to the first key with a window over its max, so one user's
|
|
1610
|
-
refused requests don't spend the tenant's budget. The 429's Retry-After is the longest wait of the windows that refused. A route is in `signedIn` (auth required, or optional with
|
|
1611
|
-
a user), `public` (no auth, or optional without a user) or the class its fitting names with `.rateLimit(name)`.
|
|
1612
|
-
|
|
1613
|
-
```typescript
|
|
1614
|
-
interface RateLimitClassesConfig
|
|
1615
|
-
```
|
|
1616
|
-
|
|
1617
1346
|
**`InjectOptions`** — Options for server.inject() — method, url, headers, payload for testing without HTTP.
|
|
1618
1347
|
|
|
1619
1348
|
```typescript
|
|
@@ -1632,12 +1361,6 @@ interface InjectResponse
|
|
|
1632
1361
|
interface ServerConfig
|
|
1633
1362
|
```
|
|
1634
1363
|
|
|
1635
|
-
**`InternalErrorFault`** — What `onInternalError` is told about one request that ended in an internal error.
|
|
1636
|
-
|
|
1637
|
-
```typescript
|
|
1638
|
-
interface InternalErrorFault
|
|
1639
|
-
```
|
|
1640
|
-
|
|
1641
1364
|
**`HandlerResponse`** — Standard handler response shape — statusCode, headers, body.
|
|
1642
1365
|
|
|
1643
1366
|
```typescript
|
|
@@ -1696,7 +1419,7 @@ Generates an OpenAPI 3.1 document from route registrations — schemas derived f
|
|
|
1696
1419
|
|
|
1697
1420
|
## trace
|
|
1698
1421
|
|
|
1699
|
-
Trace namespace — hand the current trace to a process outside Node
|
|
1422
|
+
Trace namespace — hand the current trace to a process outside Node and record the steps it reports back.
|
|
1700
1423
|
|
|
1701
1424
|
### `trace.traceparent`
|
|
1702
1425
|
|
|
@@ -1710,15 +1433,6 @@ W3C `traceparent` for the current trace and open step; `null` outside a traced f
|
|
|
1710
1433
|
|
|
1711
1434
|
Records steps reported as JSON lines (or objects) by an outside process under the step open now. Synchronous; never throws.
|
|
1712
1435
|
|
|
1713
|
-
### `trace.event`
|
|
1714
|
-
|
|
1715
|
-
Records one zero-length step `external:<name>` under the step open now, with an optional `capture` and `error`. A no-op outside a traced flow; never throws.
|
|
1716
|
-
|
|
1717
|
-
### `trace.tree`
|
|
1718
|
-
|
|
1719
|
-
Reads every hot trace sharing `rootId` (a request's trace and the jobs it queued) with their steps. Runs on the
|
|
1720
|
-
given `db`, so tenant policies apply: only an unrestricted connection (table owner, tests) sees every tenant's rows.
|
|
1721
|
-
|
|
1722
1436
|
### Types
|
|
1723
1437
|
|
|
1724
1438
|
**`FlowStepMeta`** — Trace metadata for one documented flow-step: its `path:symbol` graph node id and the per-argument capture projections.
|
|
@@ -1739,40 +1453,17 @@ type ExternalStepReport = z.infer<typeof externalStepReportSchema>
|
|
|
1739
1453
|
interface ExternalRecordResult
|
|
1740
1454
|
```
|
|
1741
1455
|
|
|
1742
|
-
**`TraceStepNode`** — One step of a trace. `ref` is the flow step's `path:symbol`, or `external:<name>` for a recorded or point-event step.
|
|
1743
|
-
|
|
1744
|
-
```typescript
|
|
1745
|
-
interface TraceStepNode
|
|
1746
|
-
```
|
|
1747
|
-
|
|
1748
|
-
**`TraceNode`** — One trace of the tree, with its steps ordered by `seq`.
|
|
1749
|
-
|
|
1750
|
-
```typescript
|
|
1751
|
-
interface TraceNode
|
|
1752
|
-
```
|
|
1753
|
-
|
|
1754
|
-
**`TraceTree`** — The traces that share a root id, ordered by when they opened.
|
|
1755
|
-
|
|
1756
|
-
```typescript
|
|
1757
|
-
interface TraceTree
|
|
1758
|
-
```
|
|
1759
|
-
|
|
1760
1456
|
## data
|
|
1761
1457
|
|
|
1762
|
-
### `
|
|
1763
|
-
|
|
1764
|
-
A statement was cancelled by Postgres for running past the statement timeout a {@link withTimeouts} call set. `cause` is the driver error.
|
|
1765
|
-
|
|
1766
|
-
```typescript
|
|
1767
|
-
class StatementTimeoutError extends Error constructor(readonly statementTimeoutMs: number, cause: unknown)
|
|
1768
|
-
```
|
|
1769
|
-
|
|
1770
|
-
### `LockTimeoutError`
|
|
1458
|
+
### `tap`
|
|
1771
1459
|
|
|
1772
|
-
|
|
1460
|
+
Opens a standalone managed connection outside the manifold's pools — the
|
|
1461
|
+
sanctioned door for contexts where `pipe()` structurally cannot resolve:
|
|
1462
|
+
`worker_threads`, detached monitors, one-off scripts. Callers own the
|
|
1463
|
+
lifecycle: always `await conn.close()`.
|
|
1773
1464
|
|
|
1774
1465
|
```typescript
|
|
1775
|
-
|
|
1466
|
+
function tap(url: string, options?: ConnectOptions): ManagedConnection
|
|
1776
1467
|
```
|
|
1777
1468
|
|
|
1778
1469
|
## request
|
|
@@ -6,4 +6,10 @@ import type { DB } from './types.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function advisoryLock(db: DB, namespace: number, key: string): Promise<void>;
|
|
8
8
|
export declare function advisoryLock(db: DB, ...keys: string[]): Promise<void>;
|
|
9
|
+
/** Non-blocking advisoryLock: takes the same lock (same key forms, same hashing) if it is free
|
|
10
|
+
* and returns true, or returns false at once when another transaction holds it.
|
|
11
|
+
* A lock won is held until commit/rollback.
|
|
12
|
+
*/
|
|
13
|
+
export declare function tryAdvisoryLock(db: DB, namespace: number, key: string): Promise<boolean>;
|
|
14
|
+
export declare function tryAdvisoryLock(db: DB, ...keys: string[]): Promise<boolean>;
|
|
9
15
|
//# sourceMappingURL=advisory-lock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advisory-lock.d.ts","sourceRoot":"","sources":["../../../src/data/db/advisory-lock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"advisory-lock.d.ts","sourceRoot":"","sources":["../../../src/data/db/advisory-lock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,YAAY,CAAA;AA8BzC;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AACzF,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAM5E;;;GAGG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;AAC/F,wBAAsB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA"}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
import { sql } from './sql.js';
|
|
2
|
-
|
|
2
|
+
/** Validates the key arguments and builds the lock-argument fragment shared by
|
|
3
|
+
* advisoryLock and tryAdvisoryLock, so the two can never disagree about a key. */
|
|
4
|
+
function lockArguments(fn, first, rest) {
|
|
3
5
|
if (typeof first === 'number') {
|
|
4
6
|
const key = rest[0];
|
|
5
7
|
if (key === undefined) {
|
|
6
|
-
throw new Error(
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
throw new Error(`[pipework] ${fn}(db, namespace, key) requires a key string.\n\n` +
|
|
9
|
+
` ${fn}(db, 1001, 'my-entity') — numeric namespace + string key\n` +
|
|
10
|
+
` ${fn}(db, 'key1', 'key2') — two hashed string keys\n`);
|
|
9
11
|
}
|
|
10
|
-
|
|
11
|
-
return;
|
|
12
|
+
return sql `${first}, hashtext(${key})`;
|
|
12
13
|
}
|
|
13
14
|
if (first === undefined) {
|
|
14
|
-
throw new Error(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
if (rest.length === 0) {
|
|
20
|
-
await db.execute(sql `SELECT pg_advisory_xact_lock(hashtext(${first}))`);
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
await db.execute(sql `SELECT pg_advisory_xact_lock(hashtext(${first}), hashtext(${rest[0]}))`);
|
|
15
|
+
throw new Error(`[pipework] ${fn} requires at least one key.\n\n` +
|
|
16
|
+
` ${fn}(db, 'my-lock') — single hashed key\n` +
|
|
17
|
+
` ${fn}(db, 'key1', 'key2') — two hashed keys\n` +
|
|
18
|
+
` ${fn}(db, 1001, 'my-entity') — numeric namespace + hashed key\n`);
|
|
24
19
|
}
|
|
20
|
+
if (rest.length === 0)
|
|
21
|
+
return sql `hashtext(${first})`;
|
|
22
|
+
return sql `hashtext(${first}), hashtext(${rest[0]})`;
|
|
23
|
+
}
|
|
24
|
+
export async function advisoryLock(db, first, ...rest) {
|
|
25
|
+
const args = lockArguments('advisoryLock', first, rest);
|
|
26
|
+
await db.execute(sql `SELECT pg_advisory_xact_lock(${args})`);
|
|
27
|
+
}
|
|
28
|
+
export async function tryAdvisoryLock(db, first, ...rest) {
|
|
29
|
+
const args = lockArguments('tryAdvisoryLock', first, rest);
|
|
30
|
+
const rows = await db.execute(sql `SELECT pg_try_advisory_xact_lock(${args}) AS locked`);
|
|
31
|
+
return rows[0]?.['locked'] === true;
|
|
25
32
|
}
|
|
26
33
|
//# sourceMappingURL=advisory-lock.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advisory-lock.js","sourceRoot":"","sources":["../../../src/data/db/advisory-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"advisory-lock.js","sourceRoot":"","sources":["../../../src/data/db/advisory-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAG9B;kFACkF;AAClF,SAAS,aAAa,CAAC,EAAU,EAAE,KAAkC,EAAE,IAAc;IACnF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,cAAc,EAAE,iDAAiD;gBACjE,KAAK,EAAE,6DAA6D;gBACpE,KAAK,EAAE,sDAAsD,CAC9D,CAAA;QACH,CAAC;QACD,OAAO,GAAG,CAAA,GAAG,KAAK,cAAc,GAAG,GAAG,CAAA;IACxC,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,cAAc,EAAE,iCAAiC;YACjD,KAAK,EAAE,mDAAmD;YAC1D,KAAK,EAAE,iDAAiD;YACxD,KAAK,EAAE,+DAA+D,CACvE,CAAA;IACH,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAA,YAAY,KAAK,GAAG,CAAA;IACrD,OAAO,GAAG,CAAA,YAAY,KAAK,eAAe,IAAI,CAAC,CAAC,CAAE,GAAG,CAAA;AACvD,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAM,EAAE,KAAuB,EAAE,GAAG,IAAc;IACnF,MAAM,IAAI,GAAG,aAAa,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;IACvD,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,gCAAgC,IAAI,GAAG,CAAC,CAAA;AAC9D,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EAAM,EAAE,KAAuB,EAAE,GAAG,IAAc;IACtF,MAAM,IAAI,GAAG,aAAa,CAAC,iBAAiB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;IAC1D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,oCAAoC,IAAI,aAAa,CAAC,CAAA;IACvF,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAA;AACrC,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { pipe as getDb, pipeSystem, pipeDoor } from './db.js';
|
|
|
2
2
|
import { sql } from './sql.js';
|
|
3
3
|
import { migrateAll, migrateOne } from '../migrate/index.js';
|
|
4
4
|
import { excluded } from './excluded.js';
|
|
5
|
-
import { advisoryLock } from './advisory-lock.js';
|
|
5
|
+
import { advisoryLock, tryAdvisoryLock } from './advisory-lock.js';
|
|
6
6
|
import { serializable } from './serializable.js';
|
|
7
7
|
import { withTimeouts } from './timeouts.js';
|
|
8
8
|
import { bulkSet } from './bulk-set.js';
|
|
@@ -161,6 +161,8 @@ export declare const pipe: typeof getDb & {
|
|
|
161
161
|
excluded: typeof excluded;
|
|
162
162
|
/** Acquires a transaction-scoped advisory lock. Released at commit/rollback. */
|
|
163
163
|
advisoryLock: typeof advisoryLock;
|
|
164
|
+
/** Non-blocking advisoryLock: true if the transaction-scoped lock was won, false if another transaction holds it. */
|
|
165
|
+
tryAdvisoryLock: typeof tryAdvisoryLock;
|
|
164
166
|
/** Runs a function in a SERIALIZABLE transaction with automatic retry on serialization failures and deadlocks. */
|
|
165
167
|
serializable: typeof serializable;
|
|
166
168
|
/** Sets statement_timeout and/or lock_timeout for the current transaction in one statement, then runs fn; a statement cancelled for them rejects with StatementTimeoutError or LockTimeoutError. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/data/db/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/data/db/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAGnM,OAAO,EAAS,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAGzE,YAAY,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE3E,6EAA6E;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,6EAA6E;AAC7E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,mJAAmJ;AACnJ,eAAO,MAAM,IAAI;IACf,iQAAiQ;;IAGjQ,6QAA6Q;;IAG7Q,6EAA6E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAG7E,+RAA+R;;;;;;;;;;;;;IAkB/R,oDAAoD;;IAEpD,mDAAmD;;IAGnD,6EAA6E;;IAG7E,gFAAgF;;IAGhF,qHAAqH;;IAGrH,kHAAkH;;IAGlH,oMAAoM;;IAGpM,2GAA2G;;IAG3G,0GAA0G;;IAG1G,uNAAuN;;IAGvN,8EAA8E;;;;;;;;;;;;;;;;;;;;;;;IAE9E,qMAAqM;;IAErM,6DAA6D;;IAE7D,+LAA+L;;IAG/L,2GAA2G;;IAE3G,kNAAkN;;IAElN,gHAAgH;;IAEhH,kQAAkQ;;CAElQ,CAAA"}
|
|
@@ -3,7 +3,7 @@ import { sql } from './sql.js';
|
|
|
3
3
|
import { migrateAll, migrateOne } from '../migrate/index.js';
|
|
4
4
|
import { filter } from './filter.js';
|
|
5
5
|
import { excluded } from './excluded.js';
|
|
6
|
-
import { advisoryLock } from './advisory-lock.js';
|
|
6
|
+
import { advisoryLock, tryAdvisoryLock } from './advisory-lock.js';
|
|
7
7
|
import { serializable } from './serializable.js';
|
|
8
8
|
import { withTimeouts } from './timeouts.js';
|
|
9
9
|
import { bulkSet } from './bulk-set.js';
|
|
@@ -48,6 +48,8 @@ export const pipe = Object.assign(getDb, {
|
|
|
48
48
|
excluded,
|
|
49
49
|
/** Acquires a transaction-scoped advisory lock. Released at commit/rollback. */
|
|
50
50
|
advisoryLock,
|
|
51
|
+
/** Non-blocking advisoryLock: true if the transaction-scoped lock was won, false if another transaction holds it. */
|
|
52
|
+
tryAdvisoryLock,
|
|
51
53
|
/** Runs a function in a SERIALIZABLE transaction with automatic retry on serialization failures and deadlocks. */
|
|
52
54
|
serializable,
|
|
53
55
|
/** Sets statement_timeout and/or lock_timeout for the current transaction in one statement, then runs fn; a statement cancelled for them rejects with StatementTimeoutError or LockTimeoutError. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/data/db/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/data/db/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAEnM,qBAAqB;AACrB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAKzE,6EAA6E;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,6EAA6E;AAC7E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,mJAAmJ;AACnJ,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;IACvC,iQAAiQ;IACjQ,MAAM,EAAE,UAAU;IAElB,6QAA6Q;IAC7Q,IAAI,EAAE,QAAQ;IAEd,6EAA6E;IAC7E,MAAM;IAEN,+RAA+R;IAC/R,GAAG;IAEH,kGAAkG;IAClG,eAAe;IACf,YAAY;IACZ,kBAAkB;IAClB,eAAe;IACf,YAAY;IACZ,WAAW;IACX,qBAAqB;IACrB,OAAO;IAEP,qDAAqD;IACrD,UAAU;IACV,SAAS;IACT,SAAS;IAET,oDAAoD;IACpD,OAAO,EAAE,UAAU;IACnB,mDAAmD;IACnD,UAAU;IAEV,6EAA6E;IAC7E,QAAQ;IAER,gFAAgF;IAChF,YAAY;IAEZ,qHAAqH;IACrH,eAAe;IAEf,kHAAkH;IAClH,YAAY;IAEZ,oMAAoM;IACpM,YAAY;IAEZ,2GAA2G;IAC3G,OAAO;IAEP,0GAA0G;IAC1G,MAAM;IAEN,uNAAuN;IACvN,EAAE;IAEF,8EAA8E;IAC9E,KAAK;IACL,qMAAqM;IACrM,MAAM;IACN,6DAA6D;IAC7D,WAAW;IACX,+LAA+L;IAC/L,QAAQ;IAER,2GAA2G;IAC3G,MAAM;IACN,kNAAkN;IAClN,MAAM;IACN,gHAAgH;IAChH,MAAM,EAAE,MAAM;IACd,kQAAkQ;IAClQ,MAAM;CACP,CAAC,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface AwsCredentials {
|
|
2
|
+
readonly accessKeyId: string;
|
|
3
|
+
readonly secretAccessKey: string;
|
|
4
|
+
readonly sessionToken?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SigV4Request {
|
|
7
|
+
readonly method: string;
|
|
8
|
+
readonly url: string;
|
|
9
|
+
/** Headers to sign and send, other than host and x-amz-date, which are added. */
|
|
10
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
11
|
+
readonly body: string | Buffer;
|
|
12
|
+
readonly region: string;
|
|
13
|
+
readonly service: string;
|
|
14
|
+
readonly credentials: AwsCredentials;
|
|
15
|
+
readonly now?: Date;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Signs a request with AWS Signature Version 4 and returns the headers to send:
|
|
19
|
+
* the given ones, `x-amz-date`, `x-amz-security-token` when the credentials carry
|
|
20
|
+
* a session token, and `authorization`. `host` is signed but not returned; the
|
|
21
|
+
* HTTP client sets it from the URL.
|
|
22
|
+
*/
|
|
23
|
+
export declare function signV4(req: SigV4Request): Record<string, string>;
|
|
24
|
+
//# sourceMappingURL=sigv4.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.d.ts","sourceRoot":"","sources":["../../../src/infra/email/sigv4.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAA;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CACpB;AAkBD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwChE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createHash, createHmac } from 'node:crypto';
|
|
2
|
+
function sha256Hex(data) {
|
|
3
|
+
return createHash('sha256').update(data).digest('hex');
|
|
4
|
+
}
|
|
5
|
+
function hmac(key, data) {
|
|
6
|
+
return createHmac('sha256', key).update(data).digest();
|
|
7
|
+
}
|
|
8
|
+
function uriEncode(s) {
|
|
9
|
+
return encodeURIComponent(s).replace(/[!'()*]/g, c => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
10
|
+
}
|
|
11
|
+
function amzDate(d) {
|
|
12
|
+
return d.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Signs a request with AWS Signature Version 4 and returns the headers to send:
|
|
16
|
+
* the given ones, `x-amz-date`, `x-amz-security-token` when the credentials carry
|
|
17
|
+
* a session token, and `authorization`. `host` is signed but not returned; the
|
|
18
|
+
* HTTP client sets it from the URL.
|
|
19
|
+
*/
|
|
20
|
+
export function signV4(req) {
|
|
21
|
+
const url = new URL(req.url);
|
|
22
|
+
const stamp = amzDate(req.now ?? new Date());
|
|
23
|
+
const day = stamp.slice(0, 8);
|
|
24
|
+
const headers = {};
|
|
25
|
+
for (const [name, value] of Object.entries(req.headers))
|
|
26
|
+
headers[name.toLowerCase()] = value.trim().replace(/\s+/g, ' ');
|
|
27
|
+
headers['x-amz-date'] = stamp;
|
|
28
|
+
if (req.credentials.sessionToken !== undefined)
|
|
29
|
+
headers['x-amz-security-token'] = req.credentials.sessionToken;
|
|
30
|
+
const signed = { ...headers, host: url.host };
|
|
31
|
+
const names = Object.keys(signed).sort();
|
|
32
|
+
const canonicalHeaders = names.map(n => `${n}:${signed[n]}\n`).join('');
|
|
33
|
+
const signedHeaders = names.join(';');
|
|
34
|
+
const canonicalPath = url.pathname.split('/').map(uriEncode).join('/');
|
|
35
|
+
const canonicalQuery = [...url.searchParams.entries()]
|
|
36
|
+
.map(([k, v]) => [uriEncode(k), uriEncode(v)])
|
|
37
|
+
.sort((a, b) => (a[0] === b[0] ? (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0) : (a[0] < b[0] ? -1 : 1)))
|
|
38
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
39
|
+
.join('&');
|
|
40
|
+
const canonicalRequest = [
|
|
41
|
+
req.method.toUpperCase(), canonicalPath, canonicalQuery, canonicalHeaders, signedHeaders, sha256Hex(req.body),
|
|
42
|
+
].join('\n');
|
|
43
|
+
const scope = `${day}/${req.region}/${req.service}/aws4_request`;
|
|
44
|
+
const stringToSign = ['AWS4-HMAC-SHA256', stamp, scope, sha256Hex(canonicalRequest)].join('\n');
|
|
45
|
+
const kDate = hmac(`AWS4${req.credentials.secretAccessKey}`, day);
|
|
46
|
+
const kRegion = hmac(kDate, req.region);
|
|
47
|
+
const kService = hmac(kRegion, req.service);
|
|
48
|
+
const kSigning = hmac(kService, 'aws4_request');
|
|
49
|
+
const signature = createHmac('sha256', kSigning).update(stringToSign).digest('hex');
|
|
50
|
+
return {
|
|
51
|
+
...headers,
|
|
52
|
+
authorization: `AWS4-HMAC-SHA256 Credential=${req.credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=sigv4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.js","sourceRoot":"","sources":["../../../src/infra/email/sigv4.ts"],"names":[],"mappings":"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"}
|