@geekmidas/constructs 10.0.0-alpha.124 → 10.0.0-alpha.125
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/{Construct-CFW0zjdD.d.cts → Construct-127M7yrl.d.cts} +3 -2
- package/dist/{Construct-B7AXn0xH.d.mts.map → Construct-127M7yrl.d.cts.map} +1 -1
- package/dist/{Construct-CKUA-CTA.mjs → Construct-CGuc_Ijk.mjs} +2 -1
- package/dist/{Construct-CKUA-CTA.mjs.map → Construct-CGuc_Ijk.mjs.map} +1 -1
- package/dist/{Construct-DEOVauyA.cjs → Construct-DorKS0Ua.cjs} +2 -1
- package/dist/{Construct-DEOVauyA.cjs.map → Construct-DorKS0Ua.cjs.map} +1 -1
- package/dist/{Construct-B7AXn0xH.d.mts → Construct-DySlwh8o.d.mts} +3 -2
- package/dist/{Construct-CFW0zjdD.d.cts.map → Construct-DySlwh8o.d.mts.map} +1 -1
- package/dist/{Cron-bdGRSROY.d.cts → Cron-CFkpEys6.d.cts} +4 -4
- package/dist/{Cron-bdGRSROY.d.cts.map → Cron-CFkpEys6.d.cts.map} +1 -1
- package/dist/{Cron-i4Uetezh.d.mts → Cron-CQoDSu-n.d.mts} +4 -4
- package/dist/{Cron-i4Uetezh.d.mts.map → Cron-CQoDSu-n.d.mts.map} +1 -1
- package/dist/{CronBuilder-9H4BnD6W.d.mts → CronBuilder-1W-G_i15.d.mts} +5 -5
- package/dist/{CronBuilder-9H4BnD6W.d.mts.map → CronBuilder-1W-G_i15.d.mts.map} +1 -1
- package/dist/{CronBuilder-D3sF9tS_.mjs → CronBuilder-BJ5LoadF.mjs} +3 -3
- package/dist/{CronBuilder-D3sF9tS_.mjs.map → CronBuilder-BJ5LoadF.mjs.map} +1 -1
- package/dist/{CronBuilder-BXTG10u5.cjs → CronBuilder-B_NSP-Y5.cjs} +3 -3
- package/dist/{CronBuilder-BXTG10u5.cjs.map → CronBuilder-B_NSP-Y5.cjs.map} +1 -1
- package/dist/{CronBuilder-B_24LZpn.d.cts → CronBuilder-OaCRRFVk.d.cts} +5 -5
- package/dist/{CronBuilder-B_24LZpn.d.cts.map → CronBuilder-OaCRRFVk.d.cts.map} +1 -1
- package/dist/{Endpoint-DgrpG15P.d.cts → Endpoint-BEh-jW-f.d.cts} +4 -4
- package/dist/{Endpoint-CeFkSwh5.d.mts.map → Endpoint-BEh-jW-f.d.cts.map} +1 -1
- package/dist/{Endpoint-yhR2T2Wt.cjs → Endpoint-BuGFNFSB.cjs} +3 -3
- package/dist/{Endpoint-yhR2T2Wt.cjs.map → Endpoint-BuGFNFSB.cjs.map} +1 -1
- package/dist/{Endpoint-CeFkSwh5.d.mts → Endpoint-DTXDggNl.d.mts} +4 -4
- package/dist/{Endpoint-DgrpG15P.d.cts.map → Endpoint-DTXDggNl.d.mts.map} +1 -1
- package/dist/{Endpoint-gPXhHKhJ.mjs → Endpoint-VdaYKc2g.mjs} +3 -3
- package/dist/{Endpoint-gPXhHKhJ.mjs.map → Endpoint-VdaYKc2g.mjs.map} +1 -1
- package/dist/{EndpointFactory-Cc863XJS.d.cts → EndpointFactory-B2dCS9dy.d.cts} +4 -4
- package/dist/{EndpointFactory-Dbw9ugkX.d.mts.map → EndpointFactory-B2dCS9dy.d.cts.map} +1 -1
- package/dist/{EndpointFactory-CSrAyazj.cjs → EndpointFactory-C6pVda4y.cjs} +4 -4
- package/dist/{EndpointFactory-CSrAyazj.cjs.map → EndpointFactory-C6pVda4y.cjs.map} +1 -1
- package/dist/{EndpointFactory-c2ZugGig.mjs → EndpointFactory-CUpqgtaH.mjs} +4 -4
- package/dist/{EndpointFactory-c2ZugGig.mjs.map → EndpointFactory-CUpqgtaH.mjs.map} +1 -1
- package/dist/{EndpointFactory-Dbw9ugkX.d.mts → EndpointFactory-D2HXcUrJ.d.mts} +4 -4
- package/dist/{EndpointFactory-Cc863XJS.d.cts.map → EndpointFactory-D2HXcUrJ.d.mts.map} +1 -1
- package/dist/{Function-B0uZhZnU.d.cts → Function-BIEsY0Hm.d.cts} +2 -2
- package/dist/{Function-B0uZhZnU.d.cts.map → Function-BIEsY0Hm.d.cts.map} +1 -1
- package/dist/{Function-B_9R7Zy1.d.mts → Function-DfMzTGS4.d.mts} +2 -2
- package/dist/{Function-B_9R7Zy1.d.mts.map → Function-DfMzTGS4.d.mts.map} +1 -1
- package/dist/{HonoEndpointAdaptor-CN1jjUBJ.cjs → HonoEndpointAdaptor-BBTzbP38.cjs} +3 -3
- package/dist/{HonoEndpointAdaptor-CN1jjUBJ.cjs.map → HonoEndpointAdaptor-BBTzbP38.cjs.map} +1 -1
- package/dist/{HonoEndpointAdaptor-euH1oSdY.mjs → HonoEndpointAdaptor-BR_LyaFE.mjs} +3 -3
- package/dist/{HonoEndpointAdaptor-euH1oSdY.mjs.map → HonoEndpointAdaptor-BR_LyaFE.mjs.map} +1 -1
- package/dist/{ObjectSubscriberBuilder-C0WUU-ov.d.mts → ObjectSubscriberBuilder-HmBwFn2o.d.mts} +4 -4
- package/dist/{ObjectSubscriberBuilder-B4j3zgCZ.d.cts.map → ObjectSubscriberBuilder-HmBwFn2o.d.mts.map} +1 -1
- package/dist/{ObjectSubscriberBuilder-B4j3zgCZ.d.cts → ObjectSubscriberBuilder-l-64yUiF.d.cts} +4 -4
- package/dist/{ObjectSubscriberBuilder-C0WUU-ov.d.mts.map → ObjectSubscriberBuilder-l-64yUiF.d.cts.map} +1 -1
- package/dist/ProcessorBuilder-B2_stA8f.d.mts +216 -0
- package/dist/ProcessorBuilder-B2_stA8f.d.mts.map +1 -0
- package/dist/ProcessorBuilder-C62bIOwj.d.cts +216 -0
- package/dist/ProcessorBuilder-C62bIOwj.d.cts.map +1 -0
- package/dist/{Queue-B-dDXyjF.d.mts → Queue-BnK3UH8r.d.mts} +3 -3
- package/dist/{Queue-B-dDXyjF.d.mts.map → Queue-BnK3UH8r.d.mts.map} +1 -1
- package/dist/{Queue-JbIjVtTf.d.cts → Queue-C4rijiM7.d.cts} +3 -3
- package/dist/{Queue-JbIjVtTf.d.cts.map → Queue-C4rijiM7.d.cts.map} +1 -1
- package/dist/{Queue-BhuofM3k.cjs → Queue-D4Iaidrs.cjs} +3 -3
- package/dist/{Queue-BhuofM3k.cjs.map → Queue-D4Iaidrs.cjs.map} +1 -1
- package/dist/{Queue-cmhqEBOB.mjs → Queue-u8w8_HpE.mjs} +3 -3
- package/dist/{Queue-cmhqEBOB.mjs.map → Queue-u8w8_HpE.mjs.map} +1 -1
- package/dist/{QueueBuilder-DXu1qxT1.mjs → QueueBuilder-2wP5lEC8.mjs} +2 -2
- package/dist/{QueueBuilder-DXu1qxT1.mjs.map → QueueBuilder-2wP5lEC8.mjs.map} +1 -1
- package/dist/{QueueBuilder-48W-q8In.d.mts → QueueBuilder-B3vL1ED2.d.mts} +2 -2
- package/dist/{QueueBuilder-48W-q8In.d.mts.map → QueueBuilder-B3vL1ED2.d.mts.map} +1 -1
- package/dist/{QueueBuilder-MfpkJ3R9.d.cts → QueueBuilder-BcPBQSSX.d.cts} +2 -2
- package/dist/{QueueBuilder-MfpkJ3R9.d.cts.map → QueueBuilder-BcPBQSSX.d.cts.map} +1 -1
- package/dist/{QueueBuilder-DdU2klPu.cjs → QueueBuilder-BxsZ9o5z.cjs} +2 -2
- package/dist/{QueueBuilder-DdU2klPu.cjs.map → QueueBuilder-BxsZ9o5z.cjs.map} +1 -1
- package/dist/{Subscriber-Bfw5cqzz.d.cts → Subscriber-BdCtfFXL.d.cts} +3 -3
- package/dist/{Subscriber-Bfw5cqzz.d.cts.map → Subscriber-BdCtfFXL.d.cts.map} +1 -1
- package/dist/{Subscriber-Czs77h-H.d.mts → Subscriber-DDo4HFNn.d.mts} +3 -3
- package/dist/{Subscriber-Czs77h-H.d.mts.map → Subscriber-DDo4HFNn.d.mts.map} +1 -1
- package/dist/{SubscriberBuilder-DUMXzjbR.mjs → SubscriberBuilder-3msj1U2w.mjs} +2 -2
- package/dist/{SubscriberBuilder-DUMXzjbR.mjs.map → SubscriberBuilder-3msj1U2w.mjs.map} +1 -1
- package/dist/{SubscriberBuilder-CYluzubx.cjs → SubscriberBuilder-CQst6Iz3.cjs} +2 -2
- package/dist/{SubscriberBuilder-CYluzubx.cjs.map → SubscriberBuilder-CQst6Iz3.cjs.map} +1 -1
- package/dist/{Topic-D2R0r24C.mjs → Topic-DN2gYJ-p.mjs} +3 -3
- package/dist/{Topic-D2R0r24C.mjs.map → Topic-DN2gYJ-p.mjs.map} +1 -1
- package/dist/{Topic-DwS3QO0m.cjs → Topic-Dp9Q7Lj2.cjs} +3 -3
- package/dist/{Topic-DwS3QO0m.cjs.map → Topic-Dp9Q7Lj2.cjs.map} +1 -1
- package/dist/adaptors/aws.cjs +2 -2
- package/dist/adaptors/aws.d.cts +5 -5
- package/dist/adaptors/aws.d.mts +5 -5
- package/dist/adaptors/aws.mjs +3 -3
- package/dist/adaptors/hono.cjs +1 -1
- package/dist/adaptors/hono.d.cts +1 -1
- package/dist/adaptors/hono.d.mts +1 -1
- package/dist/adaptors/hono.mjs +1 -1
- package/dist/adaptors/testing.cjs +5 -5
- package/dist/adaptors/testing.d.cts +4 -4
- package/dist/adaptors/testing.d.mts +4 -4
- package/dist/adaptors/testing.mjs +5 -5
- package/dist/crons/index.cjs +2 -2
- package/dist/crons/index.d.cts +2 -2
- package/dist/crons/index.d.mts +2 -2
- package/dist/crons/index.mjs +2 -2
- package/dist/endpoints/index.cjs +3 -3
- package/dist/endpoints/index.d.cts +3 -3
- package/dist/endpoints/index.d.mts +3 -3
- package/dist/endpoints/index.mjs +3 -3
- package/dist/file-server.cjs +101 -31
- package/dist/file-server.cjs.map +1 -1
- package/dist/file-server.d.cts +95 -0
- package/dist/file-server.d.cts.map +1 -1
- package/dist/file-server.d.mts +95 -0
- package/dist/file-server.d.mts.map +1 -1
- package/dist/file-server.mjs +101 -33
- package/dist/file-server.mjs.map +1 -1
- package/dist/functions/index.cjs +1 -1
- package/dist/functions/index.d.cts +2 -2
- package/dist/functions/index.d.mts +2 -2
- package/dist/functions/index.mjs +1 -1
- package/dist/{functions-CTI-hDem.mjs → functions-BvIDQKAA.mjs} +3 -3
- package/dist/{functions-CTI-hDem.mjs.map → functions-BvIDQKAA.mjs.map} +1 -1
- package/dist/{functions-D7O5SGVc.cjs → functions-DLF6-IK8.cjs} +3 -3
- package/dist/{functions-D7O5SGVc.cjs.map → functions-DLF6-IK8.cjs.map} +1 -1
- package/dist/{index-Cd2w-DRL.d.cts → index-BtzMzhMA.d.cts} +3 -3
- package/dist/{index-Cd2w-DRL.d.cts.map → index-BtzMzhMA.d.cts.map} +1 -1
- package/dist/{index-aBIcAiH5.d.mts → index-DuriFjYD.d.mts} +3 -3
- package/dist/{index-aBIcAiH5.d.mts.map → index-DuriFjYD.d.mts.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/pattern-C1CEcglD.mjs +241 -0
- package/dist/pattern-C1CEcglD.mjs.map +1 -0
- package/dist/pattern-QFaUIr77.cjs +288 -0
- package/dist/pattern-QFaUIr77.cjs.map +1 -0
- package/dist/processors/index.cjs +214 -0
- package/dist/processors/index.cjs.map +1 -0
- package/dist/processors/index.d.cts +78 -0
- package/dist/processors/index.d.cts.map +1 -0
- package/dist/processors/index.d.mts +78 -0
- package/dist/processors/index.d.mts.map +1 -0
- package/dist/processors/index.mjs +193 -0
- package/dist/processors/index.mjs.map +1 -0
- package/dist/queue/index.cjs +2 -2
- package/dist/queue/index.d.cts +2 -2
- package/dist/queue/index.d.mts +2 -2
- package/dist/queue/index.mjs +2 -2
- package/dist/rest-api.cjs +1 -1
- package/dist/rest-api.d.cts +2 -2
- package/dist/rest-api.d.mts +2 -2
- package/dist/rest-api.mjs +1 -1
- package/dist/subscribers/index.cjs +1 -1
- package/dist/subscribers/index.d.cts +2 -2
- package/dist/subscribers/index.d.mts +2 -2
- package/dist/subscribers/index.mjs +1 -1
- package/dist/topic/index.cjs +1 -1
- package/dist/topic/index.d.cts +1 -1
- package/dist/topic/index.d.mts +1 -1
- package/dist/topic/index.mjs +1 -1
- package/dist/worker.cjs +4 -4
- package/dist/worker.d.cts +7 -7
- package/dist/worker.d.mts +7 -7
- package/dist/worker.mjs +4 -4
- package/package.json +41 -31
package/dist/file-server.d.cts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { n as StandardSchemaV1 } from "./index-DdRjYhiJ.cjs";
|
|
1
2
|
import { i as Declarable, n as Construct } from "./construct-interface-B1AfqRl4.cjs";
|
|
3
|
+
import { n as Telemetry } from "./telemetry-B48RLjyk.cjs";
|
|
2
4
|
import { r as ObjectExpiry } from "./expire-C586zznE.cjs";
|
|
5
|
+
import { f as PatternParams, i as Processor, t as ProcessorBuilder } from "./ProcessorBuilder-C62bIOwj.cjs";
|
|
6
|
+
import { Logger } from "@geekmidas/logger";
|
|
3
7
|
import { Service } from "@geekmidas/services";
|
|
4
8
|
import { ConstructName, Declaration } from "@geekmidas/manifest";
|
|
5
9
|
import { StorageClient } from "@geekmidas/storage";
|
|
@@ -58,6 +62,26 @@ export interface FileServerClient<TOpen extends string = never> extends StorageC
|
|
|
58
62
|
* @param expiresIn - minutes, matching `getUploadURL`.
|
|
59
63
|
*/
|
|
60
64
|
signedUrl(key: string, expiresIn?: number): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* The address of a processor's derivative of an open object — the
|
|
67
|
+
* thumbnail, not the original.
|
|
68
|
+
*
|
|
69
|
+
* @throws {NotOpen} when the key matches no declared pattern.
|
|
70
|
+
* @throws {ProcessorNotOnThisServer} for another file server's processor.
|
|
71
|
+
*/
|
|
72
|
+
processedUrl<TPattern extends string, TSchema extends StandardSchemaV1 | undefined>(processor: Processor<TPattern, TSchema, any, any>, params: ProcessorUrlParams<TPattern, TSchema>, key: string): string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* What addresses a derivative: the values the processor's schema accepts —
|
|
76
|
+
* its input, since these go into a path — or, without one, the raw strings.
|
|
77
|
+
*/
|
|
78
|
+
export type ProcessorUrlParams<TPattern extends string, TSchema extends StandardSchemaV1 | undefined> = TSchema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<TSchema> : PatternParams<TPattern>;
|
|
79
|
+
/** A processed URL was asked of a file server the processor is not on. */
|
|
80
|
+
export declare class ProcessorNotOnThisServer extends Error {
|
|
81
|
+
readonly pattern: string;
|
|
82
|
+
readonly server: string;
|
|
83
|
+
readonly expected: string;
|
|
84
|
+
constructor(pattern: string, server: string, expected: string);
|
|
61
85
|
}
|
|
62
86
|
export interface FileServerOptions<TOpen extends string = never> {
|
|
63
87
|
/**
|
|
@@ -74,6 +98,17 @@ export interface FileServerOptions<TOpen extends string = never> {
|
|
|
74
98
|
* refuse to serve unsigned.
|
|
75
99
|
*/
|
|
76
100
|
open?: readonly TOpen[];
|
|
101
|
+
/**
|
|
102
|
+
* Open paths whose objects never change once written — keyed by a content
|
|
103
|
+
* hash or a file id — so every client may keep them forever: the edge
|
|
104
|
+
* sends `Cache-Control: public, max-age=31536000, immutable`, over
|
|
105
|
+
* whatever the object was stored with.
|
|
106
|
+
*
|
|
107
|
+
* A subset of `open`, because a signed object is never served by the edge.
|
|
108
|
+
* Only say it of paths whose keys are written once: a client holding an
|
|
109
|
+
* immutable copy never asks again.
|
|
110
|
+
*/
|
|
111
|
+
immutable?: readonly string[];
|
|
77
112
|
/** Keep previous versions of an object. */
|
|
78
113
|
versioned?: boolean;
|
|
79
114
|
/**
|
|
@@ -82,6 +117,20 @@ export interface FileServerOptions<TOpen extends string = never> {
|
|
|
82
117
|
* server vends, so it cannot be given with `origin`.
|
|
83
118
|
*/
|
|
84
119
|
expire?: ObjectExpiry;
|
|
120
|
+
/**
|
|
121
|
+
* How long its processors' derivatives are kept in the bucket before it
|
|
122
|
+
* deletes them — 30 days unless said. They are remade on the next request,
|
|
123
|
+
* so this trades storage for the work of making one again.
|
|
124
|
+
*/
|
|
125
|
+
derived?: {
|
|
126
|
+
readonly days: number;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* What its processor unit emits — the `Telemetry` construct, as a worker
|
|
130
|
+
* takes it: each request is a span, and the deploy hands the unit the
|
|
131
|
+
* `OTEL_*` keys its stage resolves.
|
|
132
|
+
*/
|
|
133
|
+
telemetry?: Telemetry;
|
|
85
134
|
/**
|
|
86
135
|
* A bucket declared elsewhere, instead of one of this server's own.
|
|
87
136
|
*
|
|
@@ -92,6 +141,13 @@ export interface FileServerOptions<TOpen extends string = never> {
|
|
|
92
141
|
*/
|
|
93
142
|
origin?: Declarable;
|
|
94
143
|
}
|
|
144
|
+
/** An immutable pattern that no open pattern admits. */
|
|
145
|
+
export declare class ImmutableNotOpen extends Error {
|
|
146
|
+
readonly id: string;
|
|
147
|
+
readonly pattern: string;
|
|
148
|
+
readonly open: readonly string[];
|
|
149
|
+
constructor(id: string, pattern: string, open: readonly string[]);
|
|
150
|
+
}
|
|
95
151
|
/**
|
|
96
152
|
* A bucket setting given to a file server that fronts a bucket declared
|
|
97
153
|
* elsewhere — where the bucket's own construct is the one that says it.
|
|
@@ -115,14 +171,47 @@ export declare class FileServer<TName extends string = string, TOpen extends str
|
|
|
115
171
|
/** The id of the surface node, as opposed to the bucket's. */
|
|
116
172
|
readonly surfaceId: string;
|
|
117
173
|
private readonly open;
|
|
174
|
+
private readonly immutable;
|
|
118
175
|
/** The vended bucket's expiry, checked once: prefix → days. */
|
|
119
176
|
private readonly expire;
|
|
177
|
+
/** Days its processors' derivatives are kept, when it says. */
|
|
178
|
+
private readonly derivedDays;
|
|
120
179
|
/**
|
|
121
180
|
* Declared once and read by both `declare()` and `connect()`, so the keys the
|
|
122
181
|
* target publishes and the keys the client reads cannot drift.
|
|
123
182
|
*/
|
|
124
183
|
private readonly keys;
|
|
184
|
+
/**
|
|
185
|
+
* How a processor reaches the bucket: the bucket's own URL and nothing of
|
|
186
|
+
* the serving half, which a processor never needs. A field, not a getter:
|
|
187
|
+
* services are cached by object identity.
|
|
188
|
+
*/
|
|
189
|
+
private readonly origin;
|
|
125
190
|
constructor(id: ConstructName<TName>, options?: FileServerOptions<TOpen>);
|
|
191
|
+
/**
|
|
192
|
+
* A processor behind one path pattern of this server: a handler that makes
|
|
193
|
+
* a derivative of an open object on read.
|
|
194
|
+
*
|
|
195
|
+
* ```ts
|
|
196
|
+
* export const thumbnails = assets
|
|
197
|
+
* .process('/i/:width/*')
|
|
198
|
+
* .params(z.object({ width: z.enum(['64', '256', '1024']) }))
|
|
199
|
+
* .native(['sharp'])
|
|
200
|
+
* .handle(async ({ params, object }) => ({
|
|
201
|
+
* body: await sharp(await object.bytes()).resize(Number(params.width)).webp().toBuffer(),
|
|
202
|
+
* contentType: 'image/webp',
|
|
203
|
+
* cache: 'immutable',
|
|
204
|
+
* }));
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* Open paths only: a key no `open` pattern admits is answered 404, as an
|
|
208
|
+
* unsigned read of it would be.
|
|
209
|
+
*
|
|
210
|
+
* @throws {ProcessorPatternInvalid} for a pattern the edge cannot route.
|
|
211
|
+
*/
|
|
212
|
+
process<TPattern extends `/${string}/*`>(pattern: TPattern, options?: {
|
|
213
|
+
logger?: Logger;
|
|
214
|
+
}): ProcessorBuilder<TPattern>;
|
|
126
215
|
/**
|
|
127
216
|
* The served surface, as something an edge can point at.
|
|
128
217
|
*
|
|
@@ -166,6 +255,12 @@ export declare class FileServer<TName extends string = string, TOpen extends str
|
|
|
166
255
|
* does.
|
|
167
256
|
*/
|
|
168
257
|
private serves;
|
|
258
|
+
/**
|
|
259
|
+
* Whether every key a pattern admits is open: the pattern itself, each of
|
|
260
|
+
* its wildcards taken as a segment of its own, is a key an open pattern
|
|
261
|
+
* serves — `brand/logos/*` under `brand/**`, but not `**` under `brand/**`.
|
|
262
|
+
*/
|
|
263
|
+
private covers;
|
|
169
264
|
}
|
|
170
265
|
//#endregion
|
|
171
266
|
//# sourceMappingURL=file-server.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-server.d.cts","names":[],"sources":["../src/file-server.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-server.d.cts","names":[],"sources":["../src/file-server.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;YAyEY,OAAO,oBAAoB,mBAAmB,cACpD,kBACH,mBAAmB,cAAc,YAC7B,gBAAgB,SACnB;;iBAGa,iBAAiB,sCACzB;;;;;;;;;;EAUR,IAAI,KAAK,OAAO;;;;;;;;;;;EAYhB,QAAQ;;;;;;;;;;;;EAaR,UAAU,aAAa,qBAAqB;;;;;;;;EAS5C,aACC,yBACA,gBAAgB,8BAEhB,WAAW,UAAU,UAAU,oBAC/B,QAAQ,mBAAmB,UAAU,UACrC;;;;;;YAQU,mBACX,yBACA,gBAAgB,gCACb,gBAAgB,mBACjB,iBAAiB,WAAW,WAC5B,cAAc;;qBAGJ,iCAAiC;WAEnC;WACA;WACA;EAHV,YACU,iBACA,gBACA;;iBAUM,kBAAkB;;;;;;;;;;;;;;EAclC,gBAAgB;;;;;;;;;;;EAWhB;;EAEA;;;;;;EAMA,SAAS;;;;;;EAMT;aAAqB;;;;;;;EAMrB,YAAY;;;;;;;;;EASZ,SAAS;;;qBAIG,yBAAyB;WAE3B;WACA;WACA;EAHV,YACU,YACA,iBACA;;;;;;qBAgBE,6BAA6B;WAE/B;WACA;WACA;EAHV,YACU,gBACA,gBACA;;;qBAWE,gBAAgB;WAElB;WACA;EAFV,YACU,aACA;;qBAYE,WACZ,+BACA,yCACY,UAAU,OAAO,iBAAiB;mBAgC5B;WA9BT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ,iBAAiB;;WAGvD;mBAEQ;mBACA;;mBAGA;;mBAGA;;;;;mBAMA;;;;;;mBAOA;EAEjB,YACC,IAAI,cAAc,QACD,UAAS,kBAAkB;;;;;;;;;;;;;;;;;;;;;;EAwE7C,QAAQ,iCACP,SAAS,UACT;IAAW,SAAS;MAClB,iBAAiB;;;;;;;;;;;;;;;MA4BhB,UAAU;;;;;;;;;;EAoBd,WAAW;;;;;;;;;UA0CG;;;;;;;;;UAqDN;;;;;;UASA"}
|
package/dist/file-server.d.mts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { n as StandardSchemaV1 } from "./index-DdRjYhiJ.mjs";
|
|
1
2
|
import { i as Declarable, n as Construct } from "./construct-interface-ZvYQbivO.mjs";
|
|
3
|
+
import { n as Telemetry } from "./telemetry-BEoBn6GO.mjs";
|
|
2
4
|
import { r as ObjectExpiry } from "./expire-C586zznE.mjs";
|
|
5
|
+
import { f as PatternParams, i as Processor, t as ProcessorBuilder } from "./ProcessorBuilder-B2_stA8f.mjs";
|
|
3
6
|
import { ConstructName, Declaration } from "@geekmidas/manifest";
|
|
4
7
|
import { StorageClient } from "@geekmidas/storage";
|
|
5
8
|
import { Service } from "@geekmidas/services";
|
|
9
|
+
import { Logger } from "@geekmidas/logger";
|
|
6
10
|
//#region src/file-server.d.ts
|
|
7
11
|
/**
|
|
8
12
|
* A key an open pattern admits.
|
|
@@ -58,6 +62,26 @@ export interface FileServerClient<TOpen extends string = never> extends StorageC
|
|
|
58
62
|
* @param expiresIn - minutes, matching `getUploadURL`.
|
|
59
63
|
*/
|
|
60
64
|
signedUrl(key: string, expiresIn?: number): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* The address of a processor's derivative of an open object — the
|
|
67
|
+
* thumbnail, not the original.
|
|
68
|
+
*
|
|
69
|
+
* @throws {NotOpen} when the key matches no declared pattern.
|
|
70
|
+
* @throws {ProcessorNotOnThisServer} for another file server's processor.
|
|
71
|
+
*/
|
|
72
|
+
processedUrl<TPattern extends string, TSchema extends StandardSchemaV1 | undefined>(processor: Processor<TPattern, TSchema, any, any>, params: ProcessorUrlParams<TPattern, TSchema>, key: string): string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* What addresses a derivative: the values the processor's schema accepts —
|
|
76
|
+
* its input, since these go into a path — or, without one, the raw strings.
|
|
77
|
+
*/
|
|
78
|
+
export type ProcessorUrlParams<TPattern extends string, TSchema extends StandardSchemaV1 | undefined> = TSchema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<TSchema> : PatternParams<TPattern>;
|
|
79
|
+
/** A processed URL was asked of a file server the processor is not on. */
|
|
80
|
+
export declare class ProcessorNotOnThisServer extends Error {
|
|
81
|
+
readonly pattern: string;
|
|
82
|
+
readonly server: string;
|
|
83
|
+
readonly expected: string;
|
|
84
|
+
constructor(pattern: string, server: string, expected: string);
|
|
61
85
|
}
|
|
62
86
|
export interface FileServerOptions<TOpen extends string = never> {
|
|
63
87
|
/**
|
|
@@ -74,6 +98,17 @@ export interface FileServerOptions<TOpen extends string = never> {
|
|
|
74
98
|
* refuse to serve unsigned.
|
|
75
99
|
*/
|
|
76
100
|
open?: readonly TOpen[];
|
|
101
|
+
/**
|
|
102
|
+
* Open paths whose objects never change once written — keyed by a content
|
|
103
|
+
* hash or a file id — so every client may keep them forever: the edge
|
|
104
|
+
* sends `Cache-Control: public, max-age=31536000, immutable`, over
|
|
105
|
+
* whatever the object was stored with.
|
|
106
|
+
*
|
|
107
|
+
* A subset of `open`, because a signed object is never served by the edge.
|
|
108
|
+
* Only say it of paths whose keys are written once: a client holding an
|
|
109
|
+
* immutable copy never asks again.
|
|
110
|
+
*/
|
|
111
|
+
immutable?: readonly string[];
|
|
77
112
|
/** Keep previous versions of an object. */
|
|
78
113
|
versioned?: boolean;
|
|
79
114
|
/**
|
|
@@ -82,6 +117,20 @@ export interface FileServerOptions<TOpen extends string = never> {
|
|
|
82
117
|
* server vends, so it cannot be given with `origin`.
|
|
83
118
|
*/
|
|
84
119
|
expire?: ObjectExpiry;
|
|
120
|
+
/**
|
|
121
|
+
* How long its processors' derivatives are kept in the bucket before it
|
|
122
|
+
* deletes them — 30 days unless said. They are remade on the next request,
|
|
123
|
+
* so this trades storage for the work of making one again.
|
|
124
|
+
*/
|
|
125
|
+
derived?: {
|
|
126
|
+
readonly days: number;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* What its processor unit emits — the `Telemetry` construct, as a worker
|
|
130
|
+
* takes it: each request is a span, and the deploy hands the unit the
|
|
131
|
+
* `OTEL_*` keys its stage resolves.
|
|
132
|
+
*/
|
|
133
|
+
telemetry?: Telemetry;
|
|
85
134
|
/**
|
|
86
135
|
* A bucket declared elsewhere, instead of one of this server's own.
|
|
87
136
|
*
|
|
@@ -92,6 +141,13 @@ export interface FileServerOptions<TOpen extends string = never> {
|
|
|
92
141
|
*/
|
|
93
142
|
origin?: Declarable;
|
|
94
143
|
}
|
|
144
|
+
/** An immutable pattern that no open pattern admits. */
|
|
145
|
+
export declare class ImmutableNotOpen extends Error {
|
|
146
|
+
readonly id: string;
|
|
147
|
+
readonly pattern: string;
|
|
148
|
+
readonly open: readonly string[];
|
|
149
|
+
constructor(id: string, pattern: string, open: readonly string[]);
|
|
150
|
+
}
|
|
95
151
|
/**
|
|
96
152
|
* A bucket setting given to a file server that fronts a bucket declared
|
|
97
153
|
* elsewhere — where the bucket's own construct is the one that says it.
|
|
@@ -115,14 +171,47 @@ export declare class FileServer<TName extends string = string, TOpen extends str
|
|
|
115
171
|
/** The id of the surface node, as opposed to the bucket's. */
|
|
116
172
|
readonly surfaceId: string;
|
|
117
173
|
private readonly open;
|
|
174
|
+
private readonly immutable;
|
|
118
175
|
/** The vended bucket's expiry, checked once: prefix → days. */
|
|
119
176
|
private readonly expire;
|
|
177
|
+
/** Days its processors' derivatives are kept, when it says. */
|
|
178
|
+
private readonly derivedDays;
|
|
120
179
|
/**
|
|
121
180
|
* Declared once and read by both `declare()` and `connect()`, so the keys the
|
|
122
181
|
* target publishes and the keys the client reads cannot drift.
|
|
123
182
|
*/
|
|
124
183
|
private readonly keys;
|
|
184
|
+
/**
|
|
185
|
+
* How a processor reaches the bucket: the bucket's own URL and nothing of
|
|
186
|
+
* the serving half, which a processor never needs. A field, not a getter:
|
|
187
|
+
* services are cached by object identity.
|
|
188
|
+
*/
|
|
189
|
+
private readonly origin;
|
|
125
190
|
constructor(id: ConstructName<TName>, options?: FileServerOptions<TOpen>);
|
|
191
|
+
/**
|
|
192
|
+
* A processor behind one path pattern of this server: a handler that makes
|
|
193
|
+
* a derivative of an open object on read.
|
|
194
|
+
*
|
|
195
|
+
* ```ts
|
|
196
|
+
* export const thumbnails = assets
|
|
197
|
+
* .process('/i/:width/*')
|
|
198
|
+
* .params(z.object({ width: z.enum(['64', '256', '1024']) }))
|
|
199
|
+
* .native(['sharp'])
|
|
200
|
+
* .handle(async ({ params, object }) => ({
|
|
201
|
+
* body: await sharp(await object.bytes()).resize(Number(params.width)).webp().toBuffer(),
|
|
202
|
+
* contentType: 'image/webp',
|
|
203
|
+
* cache: 'immutable',
|
|
204
|
+
* }));
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* Open paths only: a key no `open` pattern admits is answered 404, as an
|
|
208
|
+
* unsigned read of it would be.
|
|
209
|
+
*
|
|
210
|
+
* @throws {ProcessorPatternInvalid} for a pattern the edge cannot route.
|
|
211
|
+
*/
|
|
212
|
+
process<TPattern extends `/${string}/*`>(pattern: TPattern, options?: {
|
|
213
|
+
logger?: Logger;
|
|
214
|
+
}): ProcessorBuilder<TPattern>;
|
|
126
215
|
/**
|
|
127
216
|
* The served surface, as something an edge can point at.
|
|
128
217
|
*
|
|
@@ -166,6 +255,12 @@ export declare class FileServer<TName extends string = string, TOpen extends str
|
|
|
166
255
|
* does.
|
|
167
256
|
*/
|
|
168
257
|
private serves;
|
|
258
|
+
/**
|
|
259
|
+
* Whether every key a pattern admits is open: the pattern itself, each of
|
|
260
|
+
* its wildcards taken as a segment of its own, is a key an open pattern
|
|
261
|
+
* serves — `brand/logos/*` under `brand/**`, but not `**` under `brand/**`.
|
|
262
|
+
*/
|
|
263
|
+
private covers;
|
|
169
264
|
}
|
|
170
265
|
//#endregion
|
|
171
266
|
//# sourceMappingURL=file-server.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-server.d.mts","names":[],"sources":["../src/file-server.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-server.d.mts","names":[],"sources":["../src/file-server.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;YAyEY,OAAO,oBAAoB,mBAAmB,cACpD,kBACH,mBAAmB,cAAc,YAC7B,gBAAgB,SACnB;;iBAGa,iBAAiB,sCACzB;;;;;;;;;;EAUR,IAAI,KAAK,OAAO;;;;;;;;;;;EAYhB,QAAQ;;;;;;;;;;;;EAaR,UAAU,aAAa,qBAAqB;;;;;;;;EAS5C,aACC,yBACA,gBAAgB,8BAEhB,WAAW,UAAU,UAAU,oBAC/B,QAAQ,mBAAmB,UAAU,UACrC;;;;;;YAQU,mBACX,yBACA,gBAAgB,gCACb,gBAAgB,mBACjB,iBAAiB,WAAW,WAC5B,cAAc;;qBAGJ,iCAAiC;WAEnC;WACA;WACA;EAHV,YACU,iBACA,gBACA;;iBAUM,kBAAkB;;;;;;;;;;;;;;EAclC,gBAAgB;;;;;;;;;;;EAWhB;;EAEA;;;;;;EAMA,SAAS;;;;;;EAMT;aAAqB;;;;;;;EAMrB,YAAY;;;;;;;;;EASZ,SAAS;;;qBAIG,yBAAyB;WAE3B;WACA;WACA;EAHV,YACU,YACA,iBACA;;;;;;qBAgBE,6BAA6B;WAE/B;WACA;WACA;EAHV,YACU,gBACA,gBACA;;;qBAWE,gBAAgB;WAElB;WACA;EAFV,YACU,aACA;;qBAYE,WACZ,+BACA,yCACY,UAAU,OAAO,iBAAiB;mBAgC5B;WA9BT,IAAI;WACJ,SAAS,QAAQ,aAAa,QAAQ,iBAAiB;;WAGvD;mBAEQ;mBACA;;mBAGA;;mBAGA;;;;;mBAMA;;;;;;mBAOA;EAEjB,YACC,IAAI,cAAc,QACD,UAAS,kBAAkB;;;;;;;;;;;;;;;;;;;;;;EAwE7C,QAAQ,iCACP,SAAS,UACT;IAAW,SAAS;MAClB,iBAAiB;;;;;;;;;;;;;;;MA4BhB,UAAU;;;;;;;;;;EAoBd,WAAW;;;;;;;;;UA0CG;;;;;;;;;UAqDN;;;;;;UASA"}
|
package/dist/file-server.mjs
CHANGED
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
import { r as expiryDays } from "./expire-CpzUAfr9.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as parsePattern, o as ProcessorBuilder, r as fillPattern } from "./pattern-C1CEcglD.mjs";
|
|
3
|
+
import { DERIVED_PREFIX, canonicalId, provideKey, serviceKey } from "@geekmidas/manifest";
|
|
3
4
|
import { createStorageClient } from "@geekmidas/storage";
|
|
5
|
+
import { DEFAULT_LOGGER } from "@geekmidas/logger/console";
|
|
4
6
|
//#region src/file-server.ts
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* the migration people actually perform is serving a bucket they already have,
|
|
32
|
-
* and naming the bucket after the construct makes that edit *add* a node rather
|
|
33
|
-
* than rename the one holding the data.
|
|
34
|
-
*/
|
|
7
|
+
/** A processed URL was asked of a file server the processor is not on. */
|
|
8
|
+
var ProcessorNotOnThisServer = class extends Error {
|
|
9
|
+
pattern;
|
|
10
|
+
server;
|
|
11
|
+
expected;
|
|
12
|
+
constructor(pattern, server, expected) {
|
|
13
|
+
super(`The processor at '${pattern}' belongs to '${server}', not '${expected}'. Ask its own file server for the URL: services.<its id>.processedUrl(…).`);
|
|
14
|
+
this.pattern = pattern;
|
|
15
|
+
this.server = server;
|
|
16
|
+
this.expected = expected;
|
|
17
|
+
this.name = "ProcessorNotOnThisServer";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/** An immutable pattern that no open pattern admits. */
|
|
21
|
+
var ImmutableNotOpen = class extends Error {
|
|
22
|
+
id;
|
|
23
|
+
pattern;
|
|
24
|
+
open;
|
|
25
|
+
constructor(id, pattern, open) {
|
|
26
|
+
super(`'${id}' says '${pattern}' is immutable, and no open path admits it` + (open.length ? ` (open: ${open.join(", ")})` : " — it opens none") + ". Only an open path is served by the edge, so only one can be cached there: add it to `open`, or narrow it to one that is.");
|
|
27
|
+
this.id = id;
|
|
28
|
+
this.pattern = pattern;
|
|
29
|
+
this.open = open;
|
|
30
|
+
this.name = "ImmutableNotOpen";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
35
33
|
/**
|
|
36
34
|
* A bucket setting given to a file server that fronts a bucket declared
|
|
37
35
|
* elsewhere — where the bucket's own construct is the one that says it.
|
|
@@ -66,21 +64,33 @@ var FileServer = class {
|
|
|
66
64
|
/** The id of the surface node, as opposed to the bucket's. */
|
|
67
65
|
surfaceId;
|
|
68
66
|
open;
|
|
67
|
+
immutable;
|
|
69
68
|
/** The vended bucket's expiry, checked once: prefix → days. */
|
|
70
69
|
expire;
|
|
70
|
+
/** Days its processors' derivatives are kept, when it says. */
|
|
71
|
+
derivedDays;
|
|
71
72
|
/**
|
|
72
73
|
* Declared once and read by both `declare()` and `connect()`, so the keys the
|
|
73
74
|
* target publishes and the keys the client reads cannot drift.
|
|
74
75
|
*/
|
|
75
76
|
keys;
|
|
77
|
+
/**
|
|
78
|
+
* How a processor reaches the bucket: the bucket's own URL and nothing of
|
|
79
|
+
* the serving half, which a processor never needs. A field, not a getter:
|
|
80
|
+
* services are cached by object identity.
|
|
81
|
+
*/
|
|
82
|
+
origin;
|
|
76
83
|
constructor(id, options = {}) {
|
|
77
84
|
this.options = options;
|
|
78
85
|
const canonical = canonicalId(id);
|
|
79
86
|
this.id = canonical;
|
|
80
87
|
this.open = options.open ?? [];
|
|
88
|
+
this.immutable = options.immutable ?? [];
|
|
89
|
+
for (const pattern of this.immutable) if (!this.covers(pattern)) throw new ImmutableNotOpen(canonical, pattern, this.open);
|
|
81
90
|
const originId = options.origin?.id ?? canonical;
|
|
82
91
|
if (options.origin && options.expire) throw new BucketOptionOnOrigin(canonical, originId, "expire");
|
|
83
92
|
this.expire = expiryDays(canonical, options.expire);
|
|
93
|
+
this.derivedDays = options.derived ? expiryDays(canonical, { [DERIVED_PREFIX]: options.derived })?.[DERIVED_PREFIX] : void 0;
|
|
84
94
|
this.surfaceId = `${canonical}Server`;
|
|
85
95
|
this.keys = {
|
|
86
96
|
origin: provideKey(originId, "url"),
|
|
@@ -90,6 +100,48 @@ var FileServer = class {
|
|
|
90
100
|
serviceName: serviceKey(canonical),
|
|
91
101
|
register: (registerOptions) => this.connect(registerOptions)
|
|
92
102
|
};
|
|
103
|
+
const originKey = this.keys.origin;
|
|
104
|
+
this.origin = {
|
|
105
|
+
serviceName: `${serviceKey(originId)}ProcessorOrigin`,
|
|
106
|
+
register: ({ envParser }) => {
|
|
107
|
+
const { url } = envParser.create((get) => ({ url: get(originKey).string() })).parse();
|
|
108
|
+
return createStorageClient(url);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A processor behind one path pattern of this server: a handler that makes
|
|
114
|
+
* a derivative of an open object on read.
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* export const thumbnails = assets
|
|
118
|
+
* .process('/i/:width/*')
|
|
119
|
+
* .params(z.object({ width: z.enum(['64', '256', '1024']) }))
|
|
120
|
+
* .native(['sharp'])
|
|
121
|
+
* .handle(async ({ params, object }) => ({
|
|
122
|
+
* body: await sharp(await object.bytes()).resize(Number(params.width)).webp().toBuffer(),
|
|
123
|
+
* contentType: 'image/webp',
|
|
124
|
+
* cache: 'immutable',
|
|
125
|
+
* }));
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* Open paths only: a key no `open` pattern admits is answered 404, as an
|
|
129
|
+
* unsigned read of it would be.
|
|
130
|
+
*
|
|
131
|
+
* @throws {ProcessorPatternInvalid} for a pattern the edge cannot route.
|
|
132
|
+
*/
|
|
133
|
+
process(pattern, options = {}) {
|
|
134
|
+
return new ProcessorBuilder({
|
|
135
|
+
parsed: parsePattern(pattern),
|
|
136
|
+
surfaceId: this.surfaceId,
|
|
137
|
+
bucketId: this.options.origin?.id ?? this.id,
|
|
138
|
+
origin: this.origin,
|
|
139
|
+
serves: (key) => this.serves(key),
|
|
140
|
+
logger: options.logger ?? DEFAULT_LOGGER,
|
|
141
|
+
native: [],
|
|
142
|
+
services: [],
|
|
143
|
+
constructs: []
|
|
144
|
+
});
|
|
93
145
|
}
|
|
94
146
|
/**
|
|
95
147
|
* The served surface, as something an edge can point at.
|
|
@@ -128,6 +180,9 @@ var FileServer = class {
|
|
|
128
180
|
id: this.surfaceId,
|
|
129
181
|
of: origin?.id ?? this.id,
|
|
130
182
|
...this.open.length ? { open: this.open } : {},
|
|
183
|
+
...this.immutable.length ? { immutable: this.immutable } : {},
|
|
184
|
+
...this.derivedDays !== void 0 ? { derivedDays: this.derivedDays } : {},
|
|
185
|
+
...this.options.telemetry ? { telemetry: this.options.telemetry.id } : {},
|
|
131
186
|
provides: [this.keys.server]
|
|
132
187
|
};
|
|
133
188
|
if (origin) return [surface];
|
|
@@ -161,7 +216,12 @@ var FileServer = class {
|
|
|
161
216
|
return Object.assign(Object.create(storage), {
|
|
162
217
|
url: serve,
|
|
163
218
|
openUrl: serve,
|
|
164
|
-
signedUrl: (key, expiresIn) => storage.getDownloadURL({ path: key }, expiresIn)
|
|
219
|
+
signedUrl: (key, expiresIn) => storage.getDownloadURL({ path: key }, expiresIn),
|
|
220
|
+
processedUrl: (processor, params, key) => {
|
|
221
|
+
if (processor.surfaceId !== this.surfaceId) throw new ProcessorNotOnThisServer(processor.pattern, processor.surfaceId, this.surfaceId);
|
|
222
|
+
if (!this.serves(key)) throw new NotOpen(key, this.open);
|
|
223
|
+
return `${base}${fillPattern(processor.parsed, params, key)}`;
|
|
224
|
+
}
|
|
165
225
|
});
|
|
166
226
|
}
|
|
167
227
|
/**
|
|
@@ -175,6 +235,14 @@ var FileServer = class {
|
|
|
175
235
|
serves(key) {
|
|
176
236
|
return this.open.some((pattern) => globToRegExp(pattern).test(key));
|
|
177
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Whether every key a pattern admits is open: the pattern itself, each of
|
|
240
|
+
* its wildcards taken as a segment of its own, is a key an open pattern
|
|
241
|
+
* serves — `brand/logos/*` under `brand/**`, but not `**` under `brand/**`.
|
|
242
|
+
*/
|
|
243
|
+
covers(pattern) {
|
|
244
|
+
return this.serves(pattern.replace(/\*\*/g, "x/x").replace(/\*/g, "x"));
|
|
245
|
+
}
|
|
178
246
|
};
|
|
179
247
|
/**
|
|
180
248
|
* One open pattern as an anchored expression.
|
|
@@ -201,6 +269,6 @@ function globToRegExp(pattern) {
|
|
|
201
269
|
return new RegExp(`^${source}$`);
|
|
202
270
|
}
|
|
203
271
|
//#endregion
|
|
204
|
-
export { BucketOptionOnOrigin, FileServer, NotOpen };
|
|
272
|
+
export { BucketOptionOnOrigin, FileServer, ImmutableNotOpen, NotOpen, ProcessorNotOnThisServer };
|
|
205
273
|
|
|
206
274
|
//# sourceMappingURL=file-server.mjs.map
|
package/dist/file-server.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-server.mjs","names":[],"sources":["../src/file-server.ts"],"sourcesContent":["/**\n * `FileServer` — a domain that serves a bucket's objects.\n *\n * `ObjectStorage` is the bucket: it writes, it presigns, and its URL is never\n * public. Serving those objects on a domain is a different thing, and it is a\n * construct of its own rather than a flag on the bucket — see\n * `docs/design/constructs-paradigm.md`, \"Why a separate construct, and what it\n * costs\", for the comparison that rules the other two shapes out.\n *\n * ```ts\n * export const uploads = new FileServer('Uploads', { open: ['brand/**'] });\n *\n * uploads.getUploadURL({ path, contentType }) // an S3 presign at the bucket\n * uploads.url('brand/logo.png') // open path — no signature\n * uploads.signedUrl('invoices/7.pdf') // one object, one recipient\n * ```\n *\n * **One construct, one client, both halves.** How a file lands in the bucket is\n * the same whether or not it is served, so splitting the upload half from the\n * serving half would be ceremony rather than safety. The client is a *superset*\n * of `StorageClient`, made literal in the type, so anything taking\n * `services.uploads` keeps compiling when the construct behind it grows a\n * serving half.\n *\n * **The id names the bucket, not the surface.** This is the detail that has to\n * be right before anything ships, because getting it backwards is destructive:\n * the migration people actually perform is serving a bucket they already have,\n * and naming the bucket after the construct makes that edit *add* a node rather\n * than rename the one holding the data.\n */\n\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\ttype Declaration,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport { createStorageClient, type StorageClient } from '@geekmidas/storage';\nimport type { Construct, Declarable } from './construct-interface';\nimport { expiryDays, type ObjectExpiry } from './expire';\n\n/**\n * A key an open pattern admits.\n *\n * The same template-literal trick `ConstructName` uses, so `open` is checked at\n * the call site rather than only at the edge:\n *\n * ```ts\n * files.url('brand/logo.png') // ok\n * files.url(`avatars/${id}.png`) // ok — a template literal still matches\n * files.url('invoices/7.pdf') // not assignable — never served unsigned\n * ```\n *\n * A single star and a double star resolve to the same type, stated rather than\n * discovered: a template literal cannot exclude `/`, so this is a prefix-and-\n * suffix guard while the *exact* pattern is enforced by the bucket policy, by\n * the cache behaviour, and by this construct's own runtime check. The type says\n * plausibly open; the infrastructure says definitely.\n */\nexport type Served<P extends string> = P extends `${infer Head}**`\n\t? `${Head}${string}`\n\t: P extends `${infer Head}*${infer Tail}`\n\t\t? `${Head}${string}${Tail}`\n\t\t: P;\n\n/** What consuming a file server hands you: a bucket client that also serves. */\nexport interface FileServerClient<TOpen extends string = never>\n\textends StorageClient {\n\t/**\n\t * The unsigned address of an open object.\n\t *\n\t * Compile-checked against the declared patterns, *and* checked again at\n\t * runtime — a JavaScript caller gets no compiler, and minting an unsigned\n\t * URL for a private object is a leak rather than a mistake.\n\t *\n\t * @throws {NotOpen} when the key matches no declared pattern.\n\t */\n\turl(key: Served<TOpen>): string;\n\n\t/**\n\t * The same thing for a key the compiler cannot see.\n\t *\n\t * A fully dynamic key does not type, which is correct and is also the case\n\t * people will hit — so the escape hatch is a named method rather than a\n\t * cast, and it runs the *same* runtime check rather than being a way around\n\t * it.\n\t *\n\t * @throws {NotOpen} when the key matches no declared pattern.\n\t */\n\topenUrl(key: string): string;\n\n\t/**\n\t * A signed address for one object and one recipient.\n\t *\n\t * Today this is an **S3 presign at the bucket**, which is what works\n\t * unchanged against MinIO locally and against S3 deployed. It is deliberately\n\t * not described as a CDN URL: CloudFront signing is a different mechanism,\n\t * with different keys, against a different host, and it needs key material\n\t * this construct does not yet declare.\n\t *\n\t * @param expiresIn - minutes, matching `getUploadURL`.\n\t */\n\tsignedUrl(key: string, expiresIn?: number): Promise<string>;\n}\n\nexport interface FileServerOptions<TOpen extends string = never> {\n\t/**\n\t * Paths served without a signature. Everything else needs one.\n\t *\n\t * Private by default: a bucket where forgetting a flag publishes user\n\t * uploads is the wrong default, so this is an exception list, and listing it\n\t * in code means exactly one set of paths is unauthenticated and it is\n\t * reviewable in a diff.\n\t *\n\t * Uploading is deliberately *not* restricted to these. Writing to a path\n\t * that happens to be open is ordinary; the only asymmetry worth enforcing is\n\t * that you cannot hand out an unsigned URL for something the server would\n\t * refuse to serve unsigned.\n\t */\n\topen?: readonly TOpen[];\n\t/** Keep previous versions of an object. */\n\tversioned?: boolean;\n\t/**\n\t * Delete the objects under each prefix this many days after they were\n\t * written — `{ 'previews/': { days: 7 } }`. A setting of the bucket this\n\t * server vends, so it cannot be given with `origin`.\n\t */\n\texpire?: ObjectExpiry;\n\t/**\n\t * A bucket declared elsewhere, instead of one of this server's own.\n\t *\n\t * `new FileServer('Uploads')` declares both nodes; this fronts a bucket that\n\t * already exists, which is also how the two edges come back when you want\n\t * them separately — a handler depending on the bucket writes, a handler\n\t * depending on the server mints URLs.\n\t */\n\torigin?: Declarable;\n}\n\n/**\n * A bucket setting given to a file server that fronts a bucket declared\n * elsewhere — where the bucket's own construct is the one that says it.\n */\nexport class BucketOptionOnOrigin extends Error {\n\tconstructor(\n\t\treadonly server: string,\n\t\treadonly origin: string,\n\t\treadonly option: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${server}' fronts '${origin}', which declares itself, so '${option}' ` +\n\t\t\t\t`belongs on the construct that declares '${origin}', not on the file server.`,\n\t\t);\n\t\tthis.name = 'BucketOptionOnOrigin';\n\t}\n}\n\n/** A key was asked to be served unsigned, and no open pattern admits it. */\nexport class NotOpen extends Error {\n\tconstructor(\n\t\treadonly key: string,\n\t\treadonly open: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`'${key}' is not served without a signature. ` +\n\t\t\t\t(open.length\n\t\t\t\t\t? `Open paths: ${open.join(', ')}. Use signedUrl() for anything else.`\n\t\t\t\t\t: 'This file server declares no open paths, so every object needs signedUrl().'),\n\t\t);\n\t\tthis.name = 'NotOpen';\n\t}\n}\n\nexport class FileServer<\n\tTName extends string = string,\n\tTOpen extends string = never,\n> implements Construct<TName, FileServerClient<TOpen>>\n{\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, FileServerClient<TOpen>>;\n\n\t/** The id of the surface node, as opposed to the bucket's. */\n\treadonly surfaceId: string;\n\n\tprivate readonly open: readonly string[];\n\n\t/** The vended bucket's expiry, checked once: prefix → days. */\n\tprivate readonly expire: Record<string, number> | undefined;\n\n\t/**\n\t * Declared once and read by both `declare()` and `connect()`, so the keys the\n\t * target publishes and the keys the client reads cannot drift.\n\t */\n\tprivate readonly keys: { origin: string; server: string };\n\n\tconstructor(\n\t\tid: ConstructName<TName>,\n\t\tprivate readonly options: FileServerOptions<TOpen> = {},\n\t) {\n\t\tconst canonical = canonicalId(id as string);\n\n\t\tthis.id = canonical as TName;\n\t\tthis.open = options.open ?? [];\n\n\t\t// The surface takes the suffix and the bucket keeps the plain id, which\n\t\t// is what makes \"serve a bucket I already have\" an edit that adds a node\n\t\t// instead of renaming the one holding the data.\n\t\tconst originId = options.origin?.id ?? canonical;\n\t\tif (options.origin && options.expire) {\n\t\t\tthrow new BucketOptionOnOrigin(canonical, originId, 'expire');\n\t\t}\n\t\tthis.expire = expiryDays(canonical, options.expire);\n\t\tthis.surfaceId = `${canonical}Server`;\n\n\t\tthis.keys = {\n\t\t\torigin: provideKey(originId, 'url'),\n\t\t\tserver: provideKey(this.surfaceId, 'url'),\n\t\t};\n\n\t\t// A field, not a getter: consumers cache services by object identity.\n\t\tthis.service = {\n\t\t\tserviceName: serviceKey(canonical) as Uncapitalize<TName>,\n\t\t\tregister: (registerOptions) => this.connect(registerOptions),\n\t\t};\n\t}\n\n\t/**\n\t * The served surface, as something an edge can point at.\n\t *\n\t * Depending on the `FileServer` itself points at the **bucket** — its\n\t * canonical node — which is right for a handler: it presigns and writes. But\n\t * a bucket's URL is never public, so a site depending on it gets nothing\n\t * inlined, which is correct and also useless.\n\t *\n\t * This is the other half: `.dependsOn([uploads.server])` points at the\n\t * surface, whose address *is* public, and is what puts\n\t * `VITE_UPLOADS_SERVER_URL` in a bundle. The same accessor shape\n\t * `database.reader()` uses, and for the same reason — one construct owning\n\t * two addresses needs a way to name the second.\n\t */\n\tget server(): Declarable {\n\t\tconst surface = this.declare().find(\n\t\t\t(declaration) => declaration.id === this.surfaceId,\n\t\t);\n\n\t\treturn {\n\t\t\tid: this.surfaceId,\n\t\t\tdeclare: () => (surface ? [surface] : []),\n\t\t};\n\t}\n\n\t/**\n\t * The bucket and the surface over it — or just the surface, when the bucket\n\t * was declared elsewhere.\n\t *\n\t * The surface names its origin through `of`, which is what makes the\n\t * reference check work: an origin resolving to nothing is a build failure,\n\t * the same guarantee `assertDerivations` already gives a reader and a schema\n\t * tenant.\n\t */\n\tdeclare(): Declaration[] {\n\t\tconst origin = this.options.origin;\n\n\t\tconst surface: Declaration = {\n\t\t\tkind: 'file-server',\n\t\t\tid: this.surfaceId,\n\t\t\tof: origin?.id ?? this.id,\n\t\t\t...(this.open.length ? { open: this.open } : {}),\n\t\t\tprovides: [this.keys.server],\n\t\t};\n\n\t\t// A vended bucket is declared here; a given one already declares itself,\n\t\t// and declaring it twice is the duplication the whole model removes.\n\t\tif (origin) return [surface];\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: 'objects',\n\t\t\t\tid: this.id,\n\t\t\t\tprovides: [this.keys.origin],\n\t\t\t\t...(this.options.versioned ? { versioned: true } : {}),\n\t\t\t\t...(this.expire ? { expire: this.expire } : {}),\n\t\t\t},\n\t\t\tsurface,\n\t\t];\n\t}\n\n\t/**\n\t * The bucket's client, with the serving half added.\n\t *\n\t * Both addresses are read here, which is also how the environment reaches a\n\t * handler: the sniffer records what this reads, so `.dependsOn([uploads])`\n\t * carries the bucket URL and the server URL without either being written\n\t * down beside the handler.\n\t */\n\tprivate async connect(\n\t\toptions: ServiceRegisterOptions,\n\t): Promise<FileServerClient<TOpen>> {\n\t\tconst { origin, server } = options.envParser\n\t\t\t.create((get) => ({\n\t\t\t\torigin: get(this.keys.origin).string(),\n\t\t\t\tserver: get(this.keys.server).string(),\n\t\t\t}))\n\t\t\t.parse();\n\n\t\tconst storage = createStorageClient(origin);\n\t\tconst base = server.replace(/\\/+$/, '');\n\n\t\tconst serve = (key: string): string => {\n\t\t\tif (!this.serves(key)) throw new NotOpen(key, this.open);\n\n\t\t\treturn `${base}/${key.replace(/^\\/+/, '')}`;\n\t\t};\n\n\t\t// Delegating rather than copying: the bucket half is whatever the driver\n\t\t// produced, including anything it grows later, and only the serving half\n\t\t// is added on top.\n\t\treturn Object.assign(Object.create(storage) as StorageClient, {\n\t\t\turl: serve as (key: Served<TOpen>) => string,\n\t\t\topenUrl: serve,\n\t\t\tsignedUrl: (key: string, expiresIn?: number) =>\n\t\t\t\tstorage.getDownloadURL({ path: key } as never, expiresIn),\n\t\t}) as FileServerClient<TOpen>;\n\t}\n\n\t/**\n\t * Whether an open pattern admits a key.\n\t *\n\t * The runtime half of {@link Served}, and stricter than it: here a single\n\t * star stops at a segment boundary and a double star does not, which is the\n\t * distinction a template-literal type cannot draw and the infrastructure\n\t * does.\n\t */\n\tprivate serves(key: string): boolean {\n\t\treturn this.open.some((pattern) => globToRegExp(pattern).test(key));\n\t}\n}\n\n/**\n * One open pattern as an anchored expression.\n *\n * A double star crosses `/`; a single star does not. Both are consumed in one\n * left-to-right pass rather than by substitution, so a pattern cannot be\n * rewritten into a placeholder that a later pass mistakes for literal text.\n */\nfunction globToRegExp(pattern: string): RegExp {\n\tlet source = '';\n\n\tfor (let index = 0; index < pattern.length; index++) {\n\t\tconst character = pattern[index];\n\n\t\tif (character !== '*') {\n\t\t\tsource += character?.replace(/[.+^${}()|[\\]\\\\?]/, '\\\\$&') ?? '';\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (pattern[index + 1] === '*') {\n\t\t\tsource += '.*';\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tsource += '[^/]*';\n\t}\n\n\treturn new RegExp(`^${source}$`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-server.mjs","names":[],"sources":["../src/file-server.ts"],"sourcesContent":["/**\n * `FileServer` — a domain that serves a bucket's objects.\n *\n * `ObjectStorage` is the bucket: it writes, it presigns, and its URL is never\n * public. Serving those objects on a domain is a different thing, and it is a\n * construct of its own rather than a flag on the bucket — see\n * `docs/design/constructs-paradigm.md`, \"Why a separate construct, and what it\n * costs\", for the comparison that rules the other two shapes out.\n *\n * ```ts\n * export const uploads = new FileServer('Uploads', { open: ['brand/**'] });\n *\n * uploads.getUploadURL({ path, contentType }) // an S3 presign at the bucket\n * uploads.url('brand/logo.png') // open path — no signature\n * uploads.signedUrl('invoices/7.pdf') // one object, one recipient\n * ```\n *\n * **One construct, one client, both halves.** How a file lands in the bucket is\n * the same whether or not it is served, so splitting the upload half from the\n * serving half would be ceremony rather than safety. The client is a *superset*\n * of `StorageClient`, made literal in the type, so anything taking\n * `services.uploads` keeps compiling when the construct behind it grows a\n * serving half.\n *\n * **The id names the bucket, not the surface.** This is the detail that has to\n * be right before anything ships, because getting it backwards is destructive:\n * the migration people actually perform is serving a bucket they already have,\n * and naming the bucket after the construct makes that edit *add* a node rather\n * than rename the one holding the data.\n */\n\nimport type { Logger } from '@geekmidas/logger';\nimport { DEFAULT_LOGGER } from '@geekmidas/logger/console';\nimport {\n\ttype ConstructName,\n\tcanonicalId,\n\tDERIVED_PREFIX,\n\ttype Declaration,\n\tprovideKey,\n\tserviceKey,\n} from '@geekmidas/manifest';\nimport type { Service, ServiceRegisterOptions } from '@geekmidas/services';\nimport { createStorageClient, type StorageClient } from '@geekmidas/storage';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { Construct, Declarable } from './construct-interface';\nimport { expiryDays, type ObjectExpiry } from './expire';\nimport type { Processor } from './processors/Processor';\nimport { ProcessorBuilder } from './processors/ProcessorBuilder';\nimport {\n\tfillPattern,\n\ttype PatternParams,\n\tparsePattern,\n} from './processors/pattern';\nimport type { Telemetry } from './telemetry';\n\n/**\n * A key an open pattern admits.\n *\n * The same template-literal trick `ConstructName` uses, so `open` is checked at\n * the call site rather than only at the edge:\n *\n * ```ts\n * files.url('brand/logo.png') // ok\n * files.url(`avatars/${id}.png`) // ok — a template literal still matches\n * files.url('invoices/7.pdf') // not assignable — never served unsigned\n * ```\n *\n * A single star and a double star resolve to the same type, stated rather than\n * discovered: a template literal cannot exclude `/`, so this is a prefix-and-\n * suffix guard while the *exact* pattern is enforced by the bucket policy, by\n * the cache behaviour, and by this construct's own runtime check. The type says\n * plausibly open; the infrastructure says definitely.\n */\nexport type Served<P extends string> = P extends `${infer Head}**`\n\t? `${Head}${string}`\n\t: P extends `${infer Head}*${infer Tail}`\n\t\t? `${Head}${string}${Tail}`\n\t\t: P;\n\n/** What consuming a file server hands you: a bucket client that also serves. */\nexport interface FileServerClient<TOpen extends string = never>\n\textends StorageClient {\n\t/**\n\t * The unsigned address of an open object.\n\t *\n\t * Compile-checked against the declared patterns, *and* checked again at\n\t * runtime — a JavaScript caller gets no compiler, and minting an unsigned\n\t * URL for a private object is a leak rather than a mistake.\n\t *\n\t * @throws {NotOpen} when the key matches no declared pattern.\n\t */\n\turl(key: Served<TOpen>): string;\n\n\t/**\n\t * The same thing for a key the compiler cannot see.\n\t *\n\t * A fully dynamic key does not type, which is correct and is also the case\n\t * people will hit — so the escape hatch is a named method rather than a\n\t * cast, and it runs the *same* runtime check rather than being a way around\n\t * it.\n\t *\n\t * @throws {NotOpen} when the key matches no declared pattern.\n\t */\n\topenUrl(key: string): string;\n\n\t/**\n\t * A signed address for one object and one recipient.\n\t *\n\t * Today this is an **S3 presign at the bucket**, which is what works\n\t * unchanged against MinIO locally and against S3 deployed. It is deliberately\n\t * not described as a CDN URL: CloudFront signing is a different mechanism,\n\t * with different keys, against a different host, and it needs key material\n\t * this construct does not yet declare.\n\t *\n\t * @param expiresIn - minutes, matching `getUploadURL`.\n\t */\n\tsignedUrl(key: string, expiresIn?: number): Promise<string>;\n\n\t/**\n\t * The address of a processor's derivative of an open object — the\n\t * thumbnail, not the original.\n\t *\n\t * @throws {NotOpen} when the key matches no declared pattern.\n\t * @throws {ProcessorNotOnThisServer} for another file server's processor.\n\t */\n\tprocessedUrl<\n\t\tTPattern extends string,\n\t\tTSchema extends StandardSchemaV1 | undefined,\n\t>(\n\t\tprocessor: Processor<TPattern, TSchema, any, any>,\n\t\tparams: ProcessorUrlParams<TPattern, TSchema>,\n\t\tkey: string,\n\t): string;\n}\n\n/**\n * What addresses a derivative: the values the processor's schema accepts —\n * its input, since these go into a path — or, without one, the raw strings.\n */\nexport type ProcessorUrlParams<\n\tTPattern extends string,\n\tTSchema extends StandardSchemaV1 | undefined,\n> = TSchema extends StandardSchemaV1\n\t? StandardSchemaV1.InferInput<TSchema>\n\t: PatternParams<TPattern>;\n\n/** A processed URL was asked of a file server the processor is not on. */\nexport class ProcessorNotOnThisServer extends Error {\n\tconstructor(\n\t\treadonly pattern: string,\n\t\treadonly server: string,\n\t\treadonly expected: string,\n\t) {\n\t\tsuper(\n\t\t\t`The processor at '${pattern}' belongs to '${server}', not '${expected}'. ` +\n\t\t\t\t`Ask its own file server for the URL: services.<its id>.processedUrl(…).`,\n\t\t);\n\t\tthis.name = 'ProcessorNotOnThisServer';\n\t}\n}\n\nexport interface FileServerOptions<TOpen extends string = never> {\n\t/**\n\t * Paths served without a signature. Everything else needs one.\n\t *\n\t * Private by default: a bucket where forgetting a flag publishes user\n\t * uploads is the wrong default, so this is an exception list, and listing it\n\t * in code means exactly one set of paths is unauthenticated and it is\n\t * reviewable in a diff.\n\t *\n\t * Uploading is deliberately *not* restricted to these. Writing to a path\n\t * that happens to be open is ordinary; the only asymmetry worth enforcing is\n\t * that you cannot hand out an unsigned URL for something the server would\n\t * refuse to serve unsigned.\n\t */\n\topen?: readonly TOpen[];\n\t/**\n\t * Open paths whose objects never change once written — keyed by a content\n\t * hash or a file id — so every client may keep them forever: the edge\n\t * sends `Cache-Control: public, max-age=31536000, immutable`, over\n\t * whatever the object was stored with.\n\t *\n\t * A subset of `open`, because a signed object is never served by the edge.\n\t * Only say it of paths whose keys are written once: a client holding an\n\t * immutable copy never asks again.\n\t */\n\timmutable?: readonly string[];\n\t/** Keep previous versions of an object. */\n\tversioned?: boolean;\n\t/**\n\t * Delete the objects under each prefix this many days after they were\n\t * written — `{ 'previews/': { days: 7 } }`. A setting of the bucket this\n\t * server vends, so it cannot be given with `origin`.\n\t */\n\texpire?: ObjectExpiry;\n\t/**\n\t * How long its processors' derivatives are kept in the bucket before it\n\t * deletes them — 30 days unless said. They are remade on the next request,\n\t * so this trades storage for the work of making one again.\n\t */\n\tderived?: { readonly days: number };\n\t/**\n\t * What its processor unit emits — the `Telemetry` construct, as a worker\n\t * takes it: each request is a span, and the deploy hands the unit the\n\t * `OTEL_*` keys its stage resolves.\n\t */\n\ttelemetry?: Telemetry;\n\t/**\n\t * A bucket declared elsewhere, instead of one of this server's own.\n\t *\n\t * `new FileServer('Uploads')` declares both nodes; this fronts a bucket that\n\t * already exists, which is also how the two edges come back when you want\n\t * them separately — a handler depending on the bucket writes, a handler\n\t * depending on the server mints URLs.\n\t */\n\torigin?: Declarable;\n}\n\n/** An immutable pattern that no open pattern admits. */\nexport class ImmutableNotOpen extends Error {\n\tconstructor(\n\t\treadonly id: string,\n\t\treadonly pattern: string,\n\t\treadonly open: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`'${id}' says '${pattern}' is immutable, and no open path admits it` +\n\t\t\t\t(open.length ? ` (open: ${open.join(', ')})` : ' — it opens none') +\n\t\t\t\t'. Only an open path is served by the edge, so only one can be ' +\n\t\t\t\t'cached there: add it to `open`, or narrow it to one that is.',\n\t\t);\n\t\tthis.name = 'ImmutableNotOpen';\n\t}\n}\n\n/**\n * A bucket setting given to a file server that fronts a bucket declared\n * elsewhere — where the bucket's own construct is the one that says it.\n */\nexport class BucketOptionOnOrigin extends Error {\n\tconstructor(\n\t\treadonly server: string,\n\t\treadonly origin: string,\n\t\treadonly option: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${server}' fronts '${origin}', which declares itself, so '${option}' ` +\n\t\t\t\t`belongs on the construct that declares '${origin}', not on the file server.`,\n\t\t);\n\t\tthis.name = 'BucketOptionOnOrigin';\n\t}\n}\n\n/** A key was asked to be served unsigned, and no open pattern admits it. */\nexport class NotOpen extends Error {\n\tconstructor(\n\t\treadonly key: string,\n\t\treadonly open: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`'${key}' is not served without a signature. ` +\n\t\t\t\t(open.length\n\t\t\t\t\t? `Open paths: ${open.join(', ')}. Use signedUrl() for anything else.`\n\t\t\t\t\t: 'This file server declares no open paths, so every object needs signedUrl().'),\n\t\t);\n\t\tthis.name = 'NotOpen';\n\t}\n}\n\nexport class FileServer<\n\tTName extends string = string,\n\tTOpen extends string = never,\n> implements Construct<TName, FileServerClient<TOpen>>\n{\n\treadonly id: TName;\n\treadonly service: Service<Uncapitalize<TName>, FileServerClient<TOpen>>;\n\n\t/** The id of the surface node, as opposed to the bucket's. */\n\treadonly surfaceId: string;\n\n\tprivate readonly open: readonly string[];\n\tprivate readonly immutable: readonly string[];\n\n\t/** The vended bucket's expiry, checked once: prefix → days. */\n\tprivate readonly expire: Record<string, number> | undefined;\n\n\t/** Days its processors' derivatives are kept, when it says. */\n\tprivate readonly derivedDays: number | undefined;\n\n\t/**\n\t * Declared once and read by both `declare()` and `connect()`, so the keys the\n\t * target publishes and the keys the client reads cannot drift.\n\t */\n\tprivate readonly keys: { origin: string; server: string };\n\n\t/**\n\t * How a processor reaches the bucket: the bucket's own URL and nothing of\n\t * the serving half, which a processor never needs. A field, not a getter:\n\t * services are cached by object identity.\n\t */\n\tprivate readonly origin: Service<string, StorageClient>;\n\n\tconstructor(\n\t\tid: ConstructName<TName>,\n\t\tprivate readonly options: FileServerOptions<TOpen> = {},\n\t) {\n\t\tconst canonical = canonicalId(id as string);\n\n\t\tthis.id = canonical as TName;\n\t\tthis.open = options.open ?? [];\n\t\tthis.immutable = options.immutable ?? [];\n\t\tfor (const pattern of this.immutable) {\n\t\t\tif (!this.covers(pattern)) {\n\t\t\t\tthrow new ImmutableNotOpen(canonical, pattern, this.open);\n\t\t\t}\n\t\t}\n\n\t\t// The surface takes the suffix and the bucket keeps the plain id, which\n\t\t// is what makes \"serve a bucket I already have\" an edit that adds a node\n\t\t// instead of renaming the one holding the data.\n\t\tconst originId = options.origin?.id ?? canonical;\n\t\tif (options.origin && options.expire) {\n\t\t\tthrow new BucketOptionOnOrigin(canonical, originId, 'expire');\n\t\t}\n\t\tthis.expire = expiryDays(canonical, options.expire);\n\t\tthis.derivedDays = options.derived\n\t\t\t? expiryDays(canonical, { [DERIVED_PREFIX]: options.derived })?.[\n\t\t\t\t\tDERIVED_PREFIX\n\t\t\t\t]\n\t\t\t: undefined;\n\t\tthis.surfaceId = `${canonical}Server`;\n\n\t\tthis.keys = {\n\t\t\torigin: provideKey(originId, 'url'),\n\t\t\tserver: provideKey(this.surfaceId, 'url'),\n\t\t};\n\n\t\t// A field, not a getter: consumers cache services by object identity.\n\t\tthis.service = {\n\t\t\tserviceName: serviceKey(canonical) as Uncapitalize<TName>,\n\t\t\tregister: (registerOptions) => this.connect(registerOptions),\n\t\t};\n\n\t\tconst originKey = this.keys.origin;\n\t\tthis.origin = {\n\t\t\tserviceName: `${serviceKey(originId)}ProcessorOrigin`,\n\t\t\tregister: ({ envParser }) => {\n\t\t\t\tconst { url } = envParser\n\t\t\t\t\t.create((get) => ({ url: get(originKey).string() }))\n\t\t\t\t\t.parse();\n\t\t\t\treturn createStorageClient(url);\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * A processor behind one path pattern of this server: a handler that makes\n\t * a derivative of an open object on read.\n\t *\n\t * ```ts\n\t * export const thumbnails = assets\n\t * .process('/i/:width/*')\n\t * .params(z.object({ width: z.enum(['64', '256', '1024']) }))\n\t * .native(['sharp'])\n\t * .handle(async ({ params, object }) => ({\n\t * body: await sharp(await object.bytes()).resize(Number(params.width)).webp().toBuffer(),\n\t * contentType: 'image/webp',\n\t * cache: 'immutable',\n\t * }));\n\t * ```\n\t *\n\t * Open paths only: a key no `open` pattern admits is answered 404, as an\n\t * unsigned read of it would be.\n\t *\n\t * @throws {ProcessorPatternInvalid} for a pattern the edge cannot route.\n\t */\n\tprocess<TPattern extends `/${string}/*`>(\n\t\tpattern: TPattern,\n\t\toptions: { logger?: Logger } = {},\n\t): ProcessorBuilder<TPattern> {\n\t\treturn new ProcessorBuilder<TPattern>({\n\t\t\tparsed: parsePattern(pattern),\n\t\t\tsurfaceId: this.surfaceId,\n\t\t\tbucketId: this.options.origin?.id ?? this.id,\n\t\t\torigin: this.origin,\n\t\t\tserves: (key) => this.serves(key),\n\t\t\tlogger: (options.logger ?? DEFAULT_LOGGER) as Logger,\n\t\t\tnative: [],\n\t\t\tservices: [],\n\t\t\tconstructs: [],\n\t\t});\n\t}\n\n\t/**\n\t * The served surface, as something an edge can point at.\n\t *\n\t * Depending on the `FileServer` itself points at the **bucket** — its\n\t * canonical node — which is right for a handler: it presigns and writes. But\n\t * a bucket's URL is never public, so a site depending on it gets nothing\n\t * inlined, which is correct and also useless.\n\t *\n\t * This is the other half: `.dependsOn([uploads.server])` points at the\n\t * surface, whose address *is* public, and is what puts\n\t * `VITE_UPLOADS_SERVER_URL` in a bundle. The same accessor shape\n\t * `database.reader()` uses, and for the same reason — one construct owning\n\t * two addresses needs a way to name the second.\n\t */\n\tget server(): Declarable {\n\t\tconst surface = this.declare().find(\n\t\t\t(declaration) => declaration.id === this.surfaceId,\n\t\t);\n\n\t\treturn {\n\t\t\tid: this.surfaceId,\n\t\t\tdeclare: () => (surface ? [surface] : []),\n\t\t};\n\t}\n\n\t/**\n\t * The bucket and the surface over it — or just the surface, when the bucket\n\t * was declared elsewhere.\n\t *\n\t * The surface names its origin through `of`, which is what makes the\n\t * reference check work: an origin resolving to nothing is a build failure,\n\t * the same guarantee `assertDerivations` already gives a reader and a schema\n\t * tenant.\n\t */\n\tdeclare(): Declaration[] {\n\t\tconst origin = this.options.origin;\n\n\t\tconst surface: Declaration = {\n\t\t\tkind: 'file-server',\n\t\t\tid: this.surfaceId,\n\t\t\tof: origin?.id ?? this.id,\n\t\t\t...(this.open.length ? { open: this.open } : {}),\n\t\t\t...(this.immutable.length ? { immutable: this.immutable } : {}),\n\t\t\t...(this.derivedDays !== undefined\n\t\t\t\t? { derivedDays: this.derivedDays }\n\t\t\t\t: {}),\n\t\t\t...(this.options.telemetry\n\t\t\t\t? { telemetry: this.options.telemetry.id }\n\t\t\t\t: {}),\n\t\t\tprovides: [this.keys.server],\n\t\t};\n\n\t\t// A vended bucket is declared here; a given one already declares itself,\n\t\t// and declaring it twice is the duplication the whole model removes.\n\t\tif (origin) return [surface];\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: 'objects',\n\t\t\t\tid: this.id,\n\t\t\t\tprovides: [this.keys.origin],\n\t\t\t\t...(this.options.versioned ? { versioned: true } : {}),\n\t\t\t\t...(this.expire ? { expire: this.expire } : {}),\n\t\t\t},\n\t\t\tsurface,\n\t\t];\n\t}\n\n\t/**\n\t * The bucket's client, with the serving half added.\n\t *\n\t * Both addresses are read here, which is also how the environment reaches a\n\t * handler: the sniffer records what this reads, so `.dependsOn([uploads])`\n\t * carries the bucket URL and the server URL without either being written\n\t * down beside the handler.\n\t */\n\tprivate async connect(\n\t\toptions: ServiceRegisterOptions,\n\t): Promise<FileServerClient<TOpen>> {\n\t\tconst { origin, server } = options.envParser\n\t\t\t.create((get) => ({\n\t\t\t\torigin: get(this.keys.origin).string(),\n\t\t\t\tserver: get(this.keys.server).string(),\n\t\t\t}))\n\t\t\t.parse();\n\n\t\tconst storage = createStorageClient(origin);\n\t\tconst base = server.replace(/\\/+$/, '');\n\n\t\tconst serve = (key: string): string => {\n\t\t\tif (!this.serves(key)) throw new NotOpen(key, this.open);\n\n\t\t\treturn `${base}/${key.replace(/^\\/+/, '')}`;\n\t\t};\n\n\t\t// Delegating rather than copying: the bucket half is whatever the driver\n\t\t// produced, including anything it grows later, and only the serving half\n\t\t// is added on top.\n\t\treturn Object.assign(Object.create(storage) as StorageClient, {\n\t\t\turl: serve as (key: Served<TOpen>) => string,\n\t\t\topenUrl: serve,\n\t\t\tsignedUrl: (key: string, expiresIn?: number) =>\n\t\t\t\tstorage.getDownloadURL({ path: key } as never, expiresIn),\n\t\t\tprocessedUrl: (\n\t\t\t\tprocessor: Processor<string, any, any, any>,\n\t\t\t\tparams: Record<string, string | number>,\n\t\t\t\tkey: string,\n\t\t\t) => {\n\t\t\t\tif (processor.surfaceId !== this.surfaceId) {\n\t\t\t\t\tthrow new ProcessorNotOnThisServer(\n\t\t\t\t\t\tprocessor.pattern,\n\t\t\t\t\t\tprocessor.surfaceId,\n\t\t\t\t\t\tthis.surfaceId,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!this.serves(key)) throw new NotOpen(key, this.open);\n\t\t\t\treturn `${base}${fillPattern(processor.parsed, params, key)}`;\n\t\t\t},\n\t\t}) as FileServerClient<TOpen>;\n\t}\n\n\t/**\n\t * Whether an open pattern admits a key.\n\t *\n\t * The runtime half of {@link Served}, and stricter than it: here a single\n\t * star stops at a segment boundary and a double star does not, which is the\n\t * distinction a template-literal type cannot draw and the infrastructure\n\t * does.\n\t */\n\tprivate serves(key: string): boolean {\n\t\treturn this.open.some((pattern) => globToRegExp(pattern).test(key));\n\t}\n\n\t/**\n\t * Whether every key a pattern admits is open: the pattern itself, each of\n\t * its wildcards taken as a segment of its own, is a key an open pattern\n\t * serves — `brand/logos/*` under `brand/**`, but not `**` under `brand/**`.\n\t */\n\tprivate covers(pattern: string): boolean {\n\t\treturn this.serves(pattern.replace(/\\*\\*/g, 'x/x').replace(/\\*/g, 'x'));\n\t}\n}\n\n/**\n * One open pattern as an anchored expression.\n *\n * A double star crosses `/`; a single star does not. Both are consumed in one\n * left-to-right pass rather than by substitution, so a pattern cannot be\n * rewritten into a placeholder that a later pass mistakes for literal text.\n */\nfunction globToRegExp(pattern: string): RegExp {\n\tlet source = '';\n\n\tfor (let index = 0; index < pattern.length; index++) {\n\t\tconst character = pattern[index];\n\n\t\tif (character !== '*') {\n\t\t\tsource += character?.replace(/[.+^${}()|[\\]\\\\?]/, '\\\\$&') ?? '';\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (pattern[index + 1] === '*') {\n\t\t\tsource += '.*';\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tsource += '[^/]*';\n\t}\n\n\treturn new RegExp(`^${source}$`);\n}\n"],"mappings":"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"}
|
package/dist/functions/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_functions = require("../functions-
|
|
2
|
+
const require_functions = require("../functions-DLF6-IK8.cjs");
|
|
3
3
|
exports.BaseFunctionBuilder = require_functions.BaseFunctionBuilder;
|
|
4
4
|
exports.Function = require_functions.Function;
|
|
5
5
|
exports.FunctionBuilder = require_functions.FunctionBuilder;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as FunctionHandler, n as Function, r as FunctionContext } from "../Function-
|
|
2
|
-
import { n as BaseFunctionBuilder, t as FunctionBuilder } from "../index-
|
|
1
|
+
import { i as FunctionHandler, n as Function, r as FunctionContext } from "../Function-BIEsY0Hm.cjs";
|
|
2
|
+
import { n as BaseFunctionBuilder, t as FunctionBuilder } from "../index-BtzMzhMA.cjs";
|
|
3
3
|
export { BaseFunctionBuilder, Function, FunctionBuilder, type FunctionContext, type FunctionHandler };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as FunctionHandler, n as Function, r as FunctionContext } from "../Function-
|
|
2
|
-
import { n as BaseFunctionBuilder, t as FunctionBuilder } from "../index-
|
|
1
|
+
import { i as FunctionHandler, n as Function, r as FunctionContext } from "../Function-DfMzTGS4.mjs";
|
|
2
|
+
import { n as BaseFunctionBuilder, t as FunctionBuilder } from "../index-DuriFjYD.mjs";
|
|
3
3
|
export { BaseFunctionBuilder, Function, FunctionBuilder, type FunctionContext, type FunctionHandler };
|
package/dist/functions/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as Function, r as BaseFunctionBuilder, t as FunctionBuilder } from "../functions-
|
|
1
|
+
import { n as Function, r as BaseFunctionBuilder, t as FunctionBuilder } from "../functions-BvIDQKAA.mjs";
|
|
2
2
|
export { BaseFunctionBuilder, Function, FunctionBuilder };
|