@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.
Files changed (157) hide show
  1. package/dist/{Construct-CFW0zjdD.d.cts → Construct-127M7yrl.d.cts} +3 -2
  2. package/dist/{Construct-B7AXn0xH.d.mts.map → Construct-127M7yrl.d.cts.map} +1 -1
  3. package/dist/{Construct-CKUA-CTA.mjs → Construct-CGuc_Ijk.mjs} +2 -1
  4. package/dist/{Construct-CKUA-CTA.mjs.map → Construct-CGuc_Ijk.mjs.map} +1 -1
  5. package/dist/{Construct-DEOVauyA.cjs → Construct-DorKS0Ua.cjs} +2 -1
  6. package/dist/{Construct-DEOVauyA.cjs.map → Construct-DorKS0Ua.cjs.map} +1 -1
  7. package/dist/{Construct-B7AXn0xH.d.mts → Construct-DySlwh8o.d.mts} +3 -2
  8. package/dist/{Construct-CFW0zjdD.d.cts.map → Construct-DySlwh8o.d.mts.map} +1 -1
  9. package/dist/{Cron-bdGRSROY.d.cts → Cron-CFkpEys6.d.cts} +4 -4
  10. package/dist/{Cron-bdGRSROY.d.cts.map → Cron-CFkpEys6.d.cts.map} +1 -1
  11. package/dist/{Cron-i4Uetezh.d.mts → Cron-CQoDSu-n.d.mts} +4 -4
  12. package/dist/{Cron-i4Uetezh.d.mts.map → Cron-CQoDSu-n.d.mts.map} +1 -1
  13. package/dist/{CronBuilder-9H4BnD6W.d.mts → CronBuilder-1W-G_i15.d.mts} +5 -5
  14. package/dist/{CronBuilder-9H4BnD6W.d.mts.map → CronBuilder-1W-G_i15.d.mts.map} +1 -1
  15. package/dist/{CronBuilder-D3sF9tS_.mjs → CronBuilder-BJ5LoadF.mjs} +3 -3
  16. package/dist/{CronBuilder-D3sF9tS_.mjs.map → CronBuilder-BJ5LoadF.mjs.map} +1 -1
  17. package/dist/{CronBuilder-BXTG10u5.cjs → CronBuilder-B_NSP-Y5.cjs} +3 -3
  18. package/dist/{CronBuilder-BXTG10u5.cjs.map → CronBuilder-B_NSP-Y5.cjs.map} +1 -1
  19. package/dist/{CronBuilder-B_24LZpn.d.cts → CronBuilder-OaCRRFVk.d.cts} +5 -5
  20. package/dist/{CronBuilder-B_24LZpn.d.cts.map → CronBuilder-OaCRRFVk.d.cts.map} +1 -1
  21. package/dist/{Endpoint-DgrpG15P.d.cts → Endpoint-BEh-jW-f.d.cts} +4 -4
  22. package/dist/{Endpoint-CeFkSwh5.d.mts.map → Endpoint-BEh-jW-f.d.cts.map} +1 -1
  23. package/dist/{Endpoint-yhR2T2Wt.cjs → Endpoint-BuGFNFSB.cjs} +3 -3
  24. package/dist/{Endpoint-yhR2T2Wt.cjs.map → Endpoint-BuGFNFSB.cjs.map} +1 -1
  25. package/dist/{Endpoint-CeFkSwh5.d.mts → Endpoint-DTXDggNl.d.mts} +4 -4
  26. package/dist/{Endpoint-DgrpG15P.d.cts.map → Endpoint-DTXDggNl.d.mts.map} +1 -1
  27. package/dist/{Endpoint-gPXhHKhJ.mjs → Endpoint-VdaYKc2g.mjs} +3 -3
  28. package/dist/{Endpoint-gPXhHKhJ.mjs.map → Endpoint-VdaYKc2g.mjs.map} +1 -1
  29. package/dist/{EndpointFactory-Cc863XJS.d.cts → EndpointFactory-B2dCS9dy.d.cts} +4 -4
  30. package/dist/{EndpointFactory-Dbw9ugkX.d.mts.map → EndpointFactory-B2dCS9dy.d.cts.map} +1 -1
  31. package/dist/{EndpointFactory-CSrAyazj.cjs → EndpointFactory-C6pVda4y.cjs} +4 -4
  32. package/dist/{EndpointFactory-CSrAyazj.cjs.map → EndpointFactory-C6pVda4y.cjs.map} +1 -1
  33. package/dist/{EndpointFactory-c2ZugGig.mjs → EndpointFactory-CUpqgtaH.mjs} +4 -4
  34. package/dist/{EndpointFactory-c2ZugGig.mjs.map → EndpointFactory-CUpqgtaH.mjs.map} +1 -1
  35. package/dist/{EndpointFactory-Dbw9ugkX.d.mts → EndpointFactory-D2HXcUrJ.d.mts} +4 -4
  36. package/dist/{EndpointFactory-Cc863XJS.d.cts.map → EndpointFactory-D2HXcUrJ.d.mts.map} +1 -1
  37. package/dist/{Function-B0uZhZnU.d.cts → Function-BIEsY0Hm.d.cts} +2 -2
  38. package/dist/{Function-B0uZhZnU.d.cts.map → Function-BIEsY0Hm.d.cts.map} +1 -1
  39. package/dist/{Function-B_9R7Zy1.d.mts → Function-DfMzTGS4.d.mts} +2 -2
  40. package/dist/{Function-B_9R7Zy1.d.mts.map → Function-DfMzTGS4.d.mts.map} +1 -1
  41. package/dist/{HonoEndpointAdaptor-CN1jjUBJ.cjs → HonoEndpointAdaptor-BBTzbP38.cjs} +3 -3
  42. package/dist/{HonoEndpointAdaptor-CN1jjUBJ.cjs.map → HonoEndpointAdaptor-BBTzbP38.cjs.map} +1 -1
  43. package/dist/{HonoEndpointAdaptor-euH1oSdY.mjs → HonoEndpointAdaptor-BR_LyaFE.mjs} +3 -3
  44. package/dist/{HonoEndpointAdaptor-euH1oSdY.mjs.map → HonoEndpointAdaptor-BR_LyaFE.mjs.map} +1 -1
  45. package/dist/{ObjectSubscriberBuilder-C0WUU-ov.d.mts → ObjectSubscriberBuilder-HmBwFn2o.d.mts} +4 -4
  46. package/dist/{ObjectSubscriberBuilder-B4j3zgCZ.d.cts.map → ObjectSubscriberBuilder-HmBwFn2o.d.mts.map} +1 -1
  47. package/dist/{ObjectSubscriberBuilder-B4j3zgCZ.d.cts → ObjectSubscriberBuilder-l-64yUiF.d.cts} +4 -4
  48. package/dist/{ObjectSubscriberBuilder-C0WUU-ov.d.mts.map → ObjectSubscriberBuilder-l-64yUiF.d.cts.map} +1 -1
  49. package/dist/ProcessorBuilder-B2_stA8f.d.mts +216 -0
  50. package/dist/ProcessorBuilder-B2_stA8f.d.mts.map +1 -0
  51. package/dist/ProcessorBuilder-C62bIOwj.d.cts +216 -0
  52. package/dist/ProcessorBuilder-C62bIOwj.d.cts.map +1 -0
  53. package/dist/{Queue-B-dDXyjF.d.mts → Queue-BnK3UH8r.d.mts} +3 -3
  54. package/dist/{Queue-B-dDXyjF.d.mts.map → Queue-BnK3UH8r.d.mts.map} +1 -1
  55. package/dist/{Queue-JbIjVtTf.d.cts → Queue-C4rijiM7.d.cts} +3 -3
  56. package/dist/{Queue-JbIjVtTf.d.cts.map → Queue-C4rijiM7.d.cts.map} +1 -1
  57. package/dist/{Queue-BhuofM3k.cjs → Queue-D4Iaidrs.cjs} +3 -3
  58. package/dist/{Queue-BhuofM3k.cjs.map → Queue-D4Iaidrs.cjs.map} +1 -1
  59. package/dist/{Queue-cmhqEBOB.mjs → Queue-u8w8_HpE.mjs} +3 -3
  60. package/dist/{Queue-cmhqEBOB.mjs.map → Queue-u8w8_HpE.mjs.map} +1 -1
  61. package/dist/{QueueBuilder-DXu1qxT1.mjs → QueueBuilder-2wP5lEC8.mjs} +2 -2
  62. package/dist/{QueueBuilder-DXu1qxT1.mjs.map → QueueBuilder-2wP5lEC8.mjs.map} +1 -1
  63. package/dist/{QueueBuilder-48W-q8In.d.mts → QueueBuilder-B3vL1ED2.d.mts} +2 -2
  64. package/dist/{QueueBuilder-48W-q8In.d.mts.map → QueueBuilder-B3vL1ED2.d.mts.map} +1 -1
  65. package/dist/{QueueBuilder-MfpkJ3R9.d.cts → QueueBuilder-BcPBQSSX.d.cts} +2 -2
  66. package/dist/{QueueBuilder-MfpkJ3R9.d.cts.map → QueueBuilder-BcPBQSSX.d.cts.map} +1 -1
  67. package/dist/{QueueBuilder-DdU2klPu.cjs → QueueBuilder-BxsZ9o5z.cjs} +2 -2
  68. package/dist/{QueueBuilder-DdU2klPu.cjs.map → QueueBuilder-BxsZ9o5z.cjs.map} +1 -1
  69. package/dist/{Subscriber-Bfw5cqzz.d.cts → Subscriber-BdCtfFXL.d.cts} +3 -3
  70. package/dist/{Subscriber-Bfw5cqzz.d.cts.map → Subscriber-BdCtfFXL.d.cts.map} +1 -1
  71. package/dist/{Subscriber-Czs77h-H.d.mts → Subscriber-DDo4HFNn.d.mts} +3 -3
  72. package/dist/{Subscriber-Czs77h-H.d.mts.map → Subscriber-DDo4HFNn.d.mts.map} +1 -1
  73. package/dist/{SubscriberBuilder-DUMXzjbR.mjs → SubscriberBuilder-3msj1U2w.mjs} +2 -2
  74. package/dist/{SubscriberBuilder-DUMXzjbR.mjs.map → SubscriberBuilder-3msj1U2w.mjs.map} +1 -1
  75. package/dist/{SubscriberBuilder-CYluzubx.cjs → SubscriberBuilder-CQst6Iz3.cjs} +2 -2
  76. package/dist/{SubscriberBuilder-CYluzubx.cjs.map → SubscriberBuilder-CQst6Iz3.cjs.map} +1 -1
  77. package/dist/{Topic-D2R0r24C.mjs → Topic-DN2gYJ-p.mjs} +3 -3
  78. package/dist/{Topic-D2R0r24C.mjs.map → Topic-DN2gYJ-p.mjs.map} +1 -1
  79. package/dist/{Topic-DwS3QO0m.cjs → Topic-Dp9Q7Lj2.cjs} +3 -3
  80. package/dist/{Topic-DwS3QO0m.cjs.map → Topic-Dp9Q7Lj2.cjs.map} +1 -1
  81. package/dist/adaptors/aws.cjs +2 -2
  82. package/dist/adaptors/aws.d.cts +5 -5
  83. package/dist/adaptors/aws.d.mts +5 -5
  84. package/dist/adaptors/aws.mjs +3 -3
  85. package/dist/adaptors/hono.cjs +1 -1
  86. package/dist/adaptors/hono.d.cts +1 -1
  87. package/dist/adaptors/hono.d.mts +1 -1
  88. package/dist/adaptors/hono.mjs +1 -1
  89. package/dist/adaptors/testing.cjs +5 -5
  90. package/dist/adaptors/testing.d.cts +4 -4
  91. package/dist/adaptors/testing.d.mts +4 -4
  92. package/dist/adaptors/testing.mjs +5 -5
  93. package/dist/crons/index.cjs +2 -2
  94. package/dist/crons/index.d.cts +2 -2
  95. package/dist/crons/index.d.mts +2 -2
  96. package/dist/crons/index.mjs +2 -2
  97. package/dist/endpoints/index.cjs +3 -3
  98. package/dist/endpoints/index.d.cts +3 -3
  99. package/dist/endpoints/index.d.mts +3 -3
  100. package/dist/endpoints/index.mjs +3 -3
  101. package/dist/file-server.cjs +101 -31
  102. package/dist/file-server.cjs.map +1 -1
  103. package/dist/file-server.d.cts +95 -0
  104. package/dist/file-server.d.cts.map +1 -1
  105. package/dist/file-server.d.mts +95 -0
  106. package/dist/file-server.d.mts.map +1 -1
  107. package/dist/file-server.mjs +101 -33
  108. package/dist/file-server.mjs.map +1 -1
  109. package/dist/functions/index.cjs +1 -1
  110. package/dist/functions/index.d.cts +2 -2
  111. package/dist/functions/index.d.mts +2 -2
  112. package/dist/functions/index.mjs +1 -1
  113. package/dist/{functions-CTI-hDem.mjs → functions-BvIDQKAA.mjs} +3 -3
  114. package/dist/{functions-CTI-hDem.mjs.map → functions-BvIDQKAA.mjs.map} +1 -1
  115. package/dist/{functions-D7O5SGVc.cjs → functions-DLF6-IK8.cjs} +3 -3
  116. package/dist/{functions-D7O5SGVc.cjs.map → functions-DLF6-IK8.cjs.map} +1 -1
  117. package/dist/{index-Cd2w-DRL.d.cts → index-BtzMzhMA.d.cts} +3 -3
  118. package/dist/{index-Cd2w-DRL.d.cts.map → index-BtzMzhMA.d.cts.map} +1 -1
  119. package/dist/{index-aBIcAiH5.d.mts → index-DuriFjYD.d.mts} +3 -3
  120. package/dist/{index-aBIcAiH5.d.mts.map → index-DuriFjYD.d.mts.map} +1 -1
  121. package/dist/index.cjs +1 -1
  122. package/dist/index.d.cts +1 -1
  123. package/dist/index.d.mts +1 -1
  124. package/dist/index.mjs +1 -1
  125. package/dist/pattern-C1CEcglD.mjs +241 -0
  126. package/dist/pattern-C1CEcglD.mjs.map +1 -0
  127. package/dist/pattern-QFaUIr77.cjs +288 -0
  128. package/dist/pattern-QFaUIr77.cjs.map +1 -0
  129. package/dist/processors/index.cjs +214 -0
  130. package/dist/processors/index.cjs.map +1 -0
  131. package/dist/processors/index.d.cts +78 -0
  132. package/dist/processors/index.d.cts.map +1 -0
  133. package/dist/processors/index.d.mts +78 -0
  134. package/dist/processors/index.d.mts.map +1 -0
  135. package/dist/processors/index.mjs +193 -0
  136. package/dist/processors/index.mjs.map +1 -0
  137. package/dist/queue/index.cjs +2 -2
  138. package/dist/queue/index.d.cts +2 -2
  139. package/dist/queue/index.d.mts +2 -2
  140. package/dist/queue/index.mjs +2 -2
  141. package/dist/rest-api.cjs +1 -1
  142. package/dist/rest-api.d.cts +2 -2
  143. package/dist/rest-api.d.mts +2 -2
  144. package/dist/rest-api.mjs +1 -1
  145. package/dist/subscribers/index.cjs +1 -1
  146. package/dist/subscribers/index.d.cts +2 -2
  147. package/dist/subscribers/index.d.mts +2 -2
  148. package/dist/subscribers/index.mjs +1 -1
  149. package/dist/topic/index.cjs +1 -1
  150. package/dist/topic/index.d.cts +1 -1
  151. package/dist/topic/index.d.mts +1 -1
  152. package/dist/topic/index.mjs +1 -1
  153. package/dist/worker.cjs +4 -4
  154. package/dist/worker.d.cts +7 -7
  155. package/dist/worker.d.mts +7 -7
  156. package/dist/worker.mjs +4 -4
  157. package/package.json +41 -31
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern-QFaUIr77.cjs","names":["Construct","servicesOf","idsOf"],"sources":["../src/processors/Processor.ts","../src/processors/ProcessorBuilder.ts","../src/processors/pattern.ts"],"sourcesContent":["import type { Logger } from '@geekmidas/logger';\nimport type { InferStandardSchema } from '@geekmidas/schema';\nimport type { Service, ServiceRecord } from '@geekmidas/services';\nimport type { StorageClient } from '@geekmidas/storage';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { Construct, ConstructType } from '../Construct';\nimport type { ParsedPattern, PatternParams } from './pattern';\n\n/**\n * Where a processor's results are kept, under its file server's bucket.\n *\n * Written through on every result marked `immutable` and read before the\n * handler runs, so a derivative is made once. Exported so the bucket's expiry\n * can name it.\n */\nexport { DERIVED_PREFIX } from '@geekmidas/manifest';\n\n/** How long a response may be kept, by a browser and by the edge. */\nexport type ProcessorCache =\n\t/** Never changes for these parameters and this key: kept for a year. */\n\t| 'immutable'\n\t/** Kept this many seconds. */\n\t| { maxAge: number }\n\t/** Not kept. */\n\t| 'none';\n\n/** What a processor handler returns. */\nexport interface ProcessorResult {\n\tbody: Uint8Array | string;\n\tcontentType: string;\n\t/**\n\t * `immutable` results are also kept in the bucket, so the next request\n\t * for them never runs the handler. Defaults to an hour, kept nowhere.\n\t */\n\tcache?: ProcessorCache;\n}\n\n/** The object a request addresses, read from the bucket on first use. */\nexport interface SourceObject {\n\treadonly key: string;\n\tbytes(): Promise<Uint8Array>;\n\tstream(): Promise<ReadableStream<Uint8Array>>;\n\t/** The type it was stored with. */\n\tcontentType(): Promise<string | undefined>;\n}\n\nexport interface ProcessorContext<\n\tTParams,\n\tTServices extends Service[],\n\tTLogger extends Logger,\n> {\n\tparams: TParams;\n\tkey: string;\n\tobject: SourceObject;\n\tlogger: TLogger;\n\tservices: ServiceRecord<TServices>;\n}\n\nexport type ProcessorHandler<\n\tTParams,\n\tTServices extends Service[],\n\tTLogger extends Logger,\n> = (\n\tcontext: ProcessorContext<TParams, TServices, TLogger>,\n) => Promise<ProcessorResult> | ProcessorResult;\n\n/** What a processor's parameters parse to: its schema's output, or the raw strings. */\nexport type ProcessorParams<\n\tTPattern extends string,\n\tTSchema extends StandardSchemaV1 | undefined,\n> = TSchema extends StandardSchemaV1\n\t? InferStandardSchema<TSchema>\n\t: PatternParams<TPattern>;\n\n/**\n * A processor — a handler behind one path pattern of a file server, which\n * makes a derivative of an open object on read: a thumbnail, a page of a PDF.\n *\n * Built from the file server (`assets.process('/i/:width/*')`), so it carries\n * the bucket it reads and the open paths it may serve. Its parameters' schema\n * is the allowlist: a request outside it is refused before anything runs, so\n * nobody can mint new work — or new cache entries — by varying a number.\n */\nexport class Processor<\n\tTPattern extends string = string,\n\tTSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n> extends Construct<TLogger, undefined, TServices> {\n\t__IS_PROCESSOR__ = true;\n\n\tstatic isProcessor(obj: unknown): obj is Processor<string, any, any, any> {\n\t\treturn Boolean(\n\t\t\tobj &&\n\t\t\t\t(obj as { __IS_PROCESSOR__?: boolean }).__IS_PROCESSOR__ === true &&\n\t\t\t\t(obj as Construct).type === ConstructType.Processor,\n\t\t);\n\t}\n\n\tconstructor(\n\t\treadonly parsed: ParsedPattern,\n\t\treadonly handler: ProcessorHandler<\n\t\t\tProcessorParams<TPattern, TSchema>,\n\t\t\tTServices,\n\t\t\tTLogger\n\t\t>,\n\t\treadonly options: {\n\t\t\t/** The file server's surface id — the unit that runs it. */\n\t\t\tsurfaceId: string;\n\t\t\t/** The bucket it reads from and keeps derivatives in. */\n\t\t\tbucketId: string;\n\t\t\t/** How it reaches that bucket. */\n\t\t\torigin: Service<string, StorageClient>;\n\t\t\t/** Whether a key is one of the file server's open paths. */\n\t\t\tserves: (key: string) => boolean;\n\t\t\tparamsSchema?: TSchema;\n\t\t\t/** Packages with native code, installed for the target. */\n\t\t\tnative: readonly string[];\n\t\t\tlogger: TLogger;\n\t\t\tservices: TServices;\n\t\t\tconstructs: string[];\n\t\t\ttimeout?: number;\n\t\t\tmemorySize?: number;\n\t\t},\n\t) {\n\t\tsuper(\n\t\t\tConstructType.Processor,\n\t\t\toptions.logger,\n\t\t\t// The bucket is reached like any service — which is also how its URL\n\t\t\t// is found by the environment sniffer.\n\t\t\t[options.origin, ...options.services] as unknown as TServices,\n\t\t\t[],\n\t\t\tundefined,\n\t\t\toptions.timeout,\n\t\t\toptions.memorySize,\n\t\t\tundefined,\n\t\t\t// The bucket is an edge of its process, so the unit running it is\n\t\t\t// handed the bucket's address.\n\t\t\t[...new Set([options.bucketId, ...options.constructs])],\n\t\t);\n\t\tthis.owner = options.surfaceId;\n\t}\n\n\t/** The pattern it answers, as written. */\n\tget pattern(): TPattern {\n\t\treturn this.parsed.pattern as TPattern;\n\t}\n\n\t/** The literal path the edge routes to it — `/i/`. */\n\tget prefix(): string {\n\t\treturn this.parsed.prefix;\n\t}\n\n\tget native(): readonly string[] {\n\t\treturn this.options.native;\n\t}\n\n\tget surfaceId(): string {\n\t\treturn this.options.surfaceId;\n\t}\n\n\tget bucketId(): string {\n\t\treturn this.options.bucketId;\n\t}\n}\n","import type { Logger } from '@geekmidas/logger';\nimport type { Service } from '@geekmidas/services';\nimport type { StorageClient } from '@geekmidas/storage';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport {\n\ttype Consumable,\n\tidsOf,\n\ttype ServicesOf,\n\tservicesOf,\n} from '../construct-interface';\nimport {\n\tProcessor,\n\ttype ProcessorHandler,\n\ttype ProcessorParams,\n} from './Processor';\nimport type { ParsedPattern } from './pattern';\n\n/** A native package named in a way no installer could resolve. */\nexport class ProcessorNativeInvalid extends Error {\n\tconstructor(readonly packageName: string) {\n\t\tsuper(\n\t\t\t`'${packageName}' is not a package name. Name the package with native code ` +\n\t\t\t\t`as it is installed — 'sharp', '@napi-rs/canvas' — and its version ` +\n\t\t\t\t`is taken from the app's package.json.`,\n\t\t);\n\t\tthis.name = 'ProcessorNativeInvalid';\n\t}\n}\n\ninterface ProcessorBuilderState<TLogger extends Logger> {\n\tparsed: ParsedPattern;\n\tsurfaceId: string;\n\tbucketId: string;\n\torigin: Service<string, StorageClient>;\n\tserves: (key: string) => boolean;\n\tlogger: TLogger;\n\tparamsSchema?: StandardSchemaV1;\n\tnative: string[];\n\tservices: Service[];\n\tconstructs: string[];\n\ttimeout?: number;\n\tmemorySize?: number;\n}\n\n/**\n * What `fileServer.process(pattern)` returns: a processor, built up one\n * immutable step at a time and finished by `.handle()`.\n */\nexport class ProcessorBuilder<\n\tTPattern extends string,\n\tTSchema extends StandardSchemaV1 | undefined = undefined,\n\tTServices extends Service[] = [],\n\tTLogger extends Logger = Logger,\n> {\n\tconstructor(private readonly state: ProcessorBuilderState<TLogger>) {}\n\n\t/**\n\t * The parameters' schema — the allowlist. Every request is parsed by it\n\t * before anything runs, and one it refuses is answered 400.\n\t */\n\tparams<T extends StandardSchemaV1>(\n\t\tschema: T,\n\t): ProcessorBuilder<TPattern, T, TServices, TLogger> {\n\t\treturn new ProcessorBuilder({ ...this.state, paramsSchema: schema });\n\t}\n\n\t/** Constructs its handler reaches, as `services.<id>`. */\n\tdependsOn<const T extends readonly Consumable[]>(\n\t\tconstructs: T,\n\t): ProcessorBuilder<\n\t\tTPattern,\n\t\tTSchema,\n\t\t[...TServices, ...ServicesOf<T>],\n\t\tTLogger\n\t> {\n\t\tconst services = servicesOf(constructs) as unknown as Service[];\n\t\treturn new ProcessorBuilder({\n\t\t\t...this.state,\n\t\t\tservices: [\n\t\t\t\t...this.state.services.filter(\n\t\t\t\t\t(service) =>\n\t\t\t\t\t\t!services.some((s) => s.serviceName === service.serviceName),\n\t\t\t\t),\n\t\t\t\t...services,\n\t\t\t],\n\t\t\tconstructs: idsOf(constructs, this.state.constructs),\n\t\t});\n\t}\n\n\t/**\n\t * Packages with native code — `sharp` — installed for the target the\n\t * processor runs on rather than bundled: linux in its image, arm64 on\n\t * Lambda.\n\t */\n\tnative(packages: readonly string[]): this {\n\t\tfor (const name of packages) {\n\t\t\tif (!/^(@[a-z0-9._~-]+\\/)?[a-z0-9._~-]+$/.test(name)) {\n\t\t\t\tthrow new ProcessorNativeInvalid(name);\n\t\t\t}\n\t\t}\n\t\treturn new ProcessorBuilder({\n\t\t\t...this.state,\n\t\t\tnative: [...new Set([...this.state.native, ...packages])],\n\t\t}) as this;\n\t}\n\n\t/** Milliseconds a request may take, where the target bounds it. */\n\ttimeout(ms: number): this {\n\t\treturn new ProcessorBuilder({ ...this.state, timeout: ms }) as this;\n\t}\n\n\t/** Megabytes of memory, where the target sets it. */\n\tmemorySize(mb: number): this {\n\t\treturn new ProcessorBuilder({ ...this.state, memorySize: mb }) as this;\n\t}\n\n\thandle(\n\t\tfn: ProcessorHandler<\n\t\t\tProcessorParams<TPattern, TSchema>,\n\t\t\tTServices,\n\t\t\tTLogger\n\t\t>,\n\t): Processor<TPattern, TSchema, TServices, TLogger> {\n\t\tconst { state } = this;\n\t\treturn new Processor<TPattern, TSchema, TServices, TLogger>(\n\t\t\tstate.parsed,\n\t\t\tfn,\n\t\t\t{\n\t\t\t\tsurfaceId: state.surfaceId,\n\t\t\t\tbucketId: state.bucketId,\n\t\t\t\torigin: state.origin,\n\t\t\t\tserves: state.serves,\n\t\t\t\t...(state.paramsSchema\n\t\t\t\t\t? { paramsSchema: state.paramsSchema as TSchema }\n\t\t\t\t\t: {}),\n\t\t\t\tnative: state.native,\n\t\t\t\tlogger: state.logger,\n\t\t\t\tservices: state.services as TServices,\n\t\t\t\tconstructs: state.constructs,\n\t\t\t\t...(state.timeout !== undefined ? { timeout: state.timeout } : {}),\n\t\t\t\t...(state.memorySize !== undefined\n\t\t\t\t\t? { memorySize: state.memorySize }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t);\n\t}\n}\n","/**\n * A processor's path pattern: literal segments, `:name` parameters, and a\n * final `*` that is the object's key.\n *\n * ```\n * /i/:width/* → /i/256/avatars/7.png { width: '256' }, 'avatars/7.png'\n * /pdf/:page/:dpi/* → /pdf/1/150/doc.pdf { page: '1', dpi: '150' }, 'doc.pdf'\n * ```\n *\n * It starts with a literal segment because the edge routes on that prefix: a\n * pattern beginning with a parameter would claim every path on the file\n * server, objects included.\n */\n\n/** The parameter names a pattern declares, as a union. */\nexport type PatternParamNames<P extends string> =\n\tP extends `${string}/:${infer Name}/${infer Rest}`\n\t\t? Name | PatternParamNames<`/${Rest}`>\n\t\t: never;\n\n/** The raw parameters a pattern matches, before its schema parses them. */\nexport type PatternParams<P extends string> = {\n\t[K in PatternParamNames<P>]: string;\n};\n\n/** A pattern a processor cannot be served on. */\nexport class ProcessorPatternInvalid extends Error {\n\tconstructor(\n\t\treadonly pattern: string,\n\t\treadonly reason: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${pattern}' is not a processor pattern: ${reason}. A pattern is a ` +\n\t\t\t\t`literal first segment, then any \\`:name\\` parameters, then \\`*\\` ` +\n\t\t\t\t`for the object's key — '/i/:width/*'.`,\n\t\t);\n\t\tthis.name = 'ProcessorPatternInvalid';\n\t}\n}\n\n/** A pattern, parsed once. */\nexport interface ParsedPattern {\n\treadonly pattern: string;\n\t/** Each segment before the key: a literal, or a parameter's name. */\n\treadonly segments: readonly (\n\t\t| { kind: 'literal'; value: string }\n\t\t| { kind: 'param'; name: string }\n\t)[];\n\t/** The parameter names, in the order they appear. */\n\treadonly params: readonly string[];\n\t/** The literal path the edge routes on — `/i/`. */\n\treadonly prefix: string;\n}\n\n/** @throws {ProcessorPatternInvalid} */\nexport function parsePattern(pattern: string): ParsedPattern {\n\tif (!pattern.startsWith('/')) {\n\t\tthrow new ProcessorPatternInvalid(pattern, 'it does not start with /');\n\t}\n\tif (!pattern.endsWith('/*')) {\n\t\tthrow new ProcessorPatternInvalid(\n\t\t\tpattern,\n\t\t\t'it does not end with /* — the key',\n\t\t);\n\t}\n\n\tconst parts = pattern.slice(1, -2).split('/');\n\tconst segments: ParsedPattern['segments'][number][] = [];\n\tconst params: string[] = [];\n\tfor (const part of parts) {\n\t\tif (part === '') {\n\t\t\tthrow new ProcessorPatternInvalid(pattern, 'it has an empty segment');\n\t\t}\n\t\tif (part.includes('*')) {\n\t\t\tthrow new ProcessorPatternInvalid(\n\t\t\t\tpattern,\n\t\t\t\t'only its last segment may be *',\n\t\t\t);\n\t\t}\n\t\tif (part.startsWith(':')) {\n\t\t\tconst name = part.slice(1);\n\t\t\tif (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {\n\t\t\t\tthrow new ProcessorPatternInvalid(\n\t\t\t\t\tpattern,\n\t\t\t\t\t`'${part}' is not a parameter name`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (params.includes(name)) {\n\t\t\t\tthrow new ProcessorPatternInvalid(pattern, `'${name}' appears twice`);\n\t\t\t}\n\t\t\tparams.push(name);\n\t\t\tsegments.push({ kind: 'param', name });\n\t\t\tcontinue;\n\t\t}\n\t\tif (!/^[A-Za-z0-9._~-]+$/.test(part)) {\n\t\t\tthrow new ProcessorPatternInvalid(\n\t\t\t\tpattern,\n\t\t\t\t`'${part}' has characters a path segment would escape`,\n\t\t\t);\n\t\t}\n\t\tsegments.push({ kind: 'literal', value: part });\n\t}\n\n\tconst first = segments[0];\n\tif (!first || first.kind !== 'literal') {\n\t\tthrow new ProcessorPatternInvalid(\n\t\t\tpattern,\n\t\t\t'its first segment is a parameter, which would claim every path',\n\t\t);\n\t}\n\n\tconst literals: string[] = [];\n\tfor (const segment of segments) {\n\t\tif (segment.kind !== 'literal') break;\n\t\tliterals.push(segment.value);\n\t}\n\n\treturn { pattern, segments, params, prefix: `/${literals.join('/')}/` };\n}\n\n/** A path the pattern matched: its raw parameters and the key. */\nexport interface PatternMatch {\n\tparams: Record<string, string>;\n\tkey: string;\n}\n\n/**\n * Match a request path, decoding each parameter and each key segment. A path\n * with an empty key, or one that decodes to a `..` segment, matches nothing.\n */\nexport function matchPattern(\n\tparsed: ParsedPattern,\n\tpath: string,\n): PatternMatch | undefined {\n\tconst parts = path.replace(/^\\/+/, '').split('/');\n\tif (parts.length <= parsed.segments.length) return undefined;\n\n\tconst params: Record<string, string> = {};\n\tfor (const [index, segment] of parsed.segments.entries()) {\n\t\tconst part = decode(parts[index] ?? '');\n\t\tif (part === undefined || part === '') return undefined;\n\t\tif (segment.kind === 'literal') {\n\t\t\tif (part !== segment.value) return undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tparams[segment.name] = part;\n\t}\n\n\tconst keyParts = parts.slice(parsed.segments.length).map(decode);\n\tif (keyParts.some((part) => part === undefined || part === '..')) {\n\t\treturn undefined;\n\t}\n\tconst key = keyParts.join('/');\n\tif (key === '' || keyParts.includes('')) return undefined;\n\n\treturn { params, key };\n}\n\n/** The path that addresses `key` through the pattern with these parameters. */\nexport function fillPattern(\n\tparsed: ParsedPattern,\n\tparams: Readonly<Record<string, string | number>>,\n\tkey: string,\n): string {\n\tconst head = parsed.segments.map((segment) => {\n\t\tif (segment.kind === 'literal') return segment.value;\n\t\tconst value = params[segment.name];\n\t\tif (value === undefined || `${value}` === '') {\n\t\t\tthrow new ProcessorParamMissing(parsed.pattern, segment.name);\n\t\t}\n\t\treturn encodeURIComponent(`${value}`);\n\t});\n\tconst tail = key\n\t\t.replace(/^\\/+/, '')\n\t\t.split('/')\n\t\t.map((part) => encodeURIComponent(part));\n\n\treturn `/${[...head, ...tail].join('/')}`;\n}\n\n/** A processed URL was asked for without one of the pattern's parameters. */\nexport class ProcessorParamMissing extends Error {\n\tconstructor(\n\t\treadonly pattern: string,\n\t\treadonly param: string,\n\t) {\n\t\tsuper(\n\t\t\t`'${pattern}' needs '${param}' to address an object, and it was not given.`,\n\t\t);\n\t\tthis.name = 'ProcessorParamMissing';\n\t}\n}\n\nfunction decode(part: string): string | undefined {\n\ttry {\n\t\treturn decodeURIComponent(part);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,214 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_pattern = require("../pattern-QFaUIr77.cjs");
3
+ const require_surfaceEnv = require("../surfaceEnv-CNimK76p.cjs");
4
+ let _geekmidas_services = require("@geekmidas/services");
5
+ let _geekmidas_manifest = require("@geekmidas/manifest");
6
+ //#region src/processors/runProcessor.ts
7
+ /** The object a request addressed is not in the bucket. */
8
+ var ProcessorSourceMissing = class extends Error {
9
+ key;
10
+ constructor(key) {
11
+ super(`'${key}' is not in the bucket, so there is nothing to process.`);
12
+ this.key = key;
13
+ this.name = "ProcessorSourceMissing";
14
+ }
15
+ };
16
+ /** What a refusal or a miss may be kept for: long enough to absorb a burst. */
17
+ const SHORT = "public, max-age=60";
18
+ /** The header a response carries, by how long it may be kept. */
19
+ function cacheControl(cache) {
20
+ if (cache === "immutable") return "public, max-age=31536000, immutable";
21
+ if (cache === "none") return "no-store";
22
+ return `public, max-age=${cache?.maxAge ?? 3600}`;
23
+ }
24
+ /** Where a processor keeps the derivative for one request. */
25
+ function derivedKey(processor, params, key) {
26
+ return `${_geekmidas_manifest.DERIVED_PREFIX}${require_pattern.fillPattern(processor.parsed, params, key).slice(1)}`;
27
+ }
28
+ /**
29
+ * Answer one request with the first processor whose pattern matches it, or
30
+ * `undefined` when none does.
31
+ *
32
+ * In order: the parameters are parsed by the processor's schema (400 when it
33
+ * refuses them); the key must be one of the file server's open paths (404
34
+ * otherwise, as an unsigned read of it would be); a derivative already in the
35
+ * bucket is answered without running anything; and only then is the handler
36
+ * run, its `immutable` result written through for next time.
37
+ */
38
+ async function handleProcessorRequest(processors, request, options) {
39
+ const method = request.method.toUpperCase();
40
+ for (const processor of processors) {
41
+ const match = require_pattern.matchPattern(processor.parsed, request.path);
42
+ if (!match) continue;
43
+ if (method !== "GET" && method !== "HEAD") return text(405, "Method Not Allowed", "no-store", { allow: "GET, HEAD" });
44
+ return (0, _geekmidas_services.runWithRequestContext)({
45
+ logger: processor.logger,
46
+ requestId: `processor-${Date.now()}`,
47
+ startTime: Date.now(),
48
+ operation: `processor ${processor.pattern}`
49
+ }, () => run(processor, match, options));
50
+ }
51
+ }
52
+ /**
53
+ * A request handler for a set of processors — what a generated entry serves
54
+ * — with its services discovered from the default environment parser: the
55
+ * process's environment and the credentials `gkm` injected.
56
+ */
57
+ function processorServer(processors, envParser = require_surfaceEnv.defaultEnvParser()) {
58
+ const serviceDiscovery = _geekmidas_services.ServiceDiscovery.getInstance(envParser);
59
+ return (request) => handleProcessorRequest(processors, request, { serviceDiscovery });
60
+ }
61
+ async function run(processor, match, options) {
62
+ const logger = processor.logger;
63
+ const fetcher = options.fetch ?? fetch;
64
+ const { key } = match;
65
+ const schema = processor.options.paramsSchema;
66
+ let params = match.params;
67
+ if (schema) {
68
+ const parsed = await schema["~standard"].validate(match.params);
69
+ if (parsed.issues) return text(400, "Bad Request", SHORT);
70
+ params = parsed.value;
71
+ }
72
+ if (key.startsWith(_geekmidas_manifest.DERIVED_PREFIX) || !processor.options.serves(key)) return text(404, "Not Found", SHORT);
73
+ const services = await options.serviceDiscovery.register(processor.services);
74
+ const storage = services[processor.options.origin.serviceName];
75
+ const derived = derivedKey(processor, match.params, key);
76
+ const kept = await read(storage, derived, fetcher);
77
+ if (kept) return {
78
+ status: 200,
79
+ headers: {
80
+ "content-type": kept.contentType ?? "application/octet-stream",
81
+ "cache-control": cacheControl("immutable"),
82
+ "x-gkm-processor": "kept"
83
+ },
84
+ body: new Uint8Array(await kept.response.arrayBuffer())
85
+ };
86
+ let source;
87
+ const load = async () => {
88
+ if (source) return source;
89
+ const found = await read(storage, key, fetcher);
90
+ if (!found) throw new ProcessorSourceMissing(key);
91
+ source = found.response;
92
+ return source;
93
+ };
94
+ const object = {
95
+ key,
96
+ bytes: async () => new Uint8Array(await (await load()).arrayBuffer()),
97
+ stream: async () => {
98
+ const body = (await load()).body;
99
+ if (!body) throw new ProcessorSourceMissing(key);
100
+ return body;
101
+ },
102
+ contentType: async () => (await load()).headers.get("content-type") ?? void 0
103
+ };
104
+ let result;
105
+ try {
106
+ result = await processor.handler({
107
+ params,
108
+ key,
109
+ object,
110
+ logger,
111
+ services
112
+ });
113
+ } catch (error) {
114
+ if (error instanceof ProcessorSourceMissing) return text(404, "Not Found", SHORT);
115
+ logger.error({
116
+ err: error,
117
+ key
118
+ }, "Processor failed");
119
+ return text(500, "Internal Server Error", "no-store");
120
+ }
121
+ const body = typeof result.body === "string" ? new TextEncoder().encode(result.body) : result.body;
122
+ if (result.cache === "immutable") await storage.upload(derived, Buffer.from(body), result.contentType).catch((error) => logger.warn({
123
+ err: error,
124
+ key: derived
125
+ }, "Could not keep derivative"));
126
+ return {
127
+ status: 200,
128
+ headers: {
129
+ "content-type": result.contentType,
130
+ "cache-control": cacheControl(result.cache),
131
+ "x-gkm-processor": "made"
132
+ },
133
+ body
134
+ };
135
+ }
136
+ /** An object through a presigned address, or nothing when it is not there. */
137
+ async function read(storage, key, fetcher) {
138
+ const response = await fetcher(await storage.getDownloadURL({ path: key }));
139
+ if (!response.ok) {
140
+ await response.body?.cancel().catch(() => void 0);
141
+ return;
142
+ }
143
+ const contentType = response.headers.get("content-type") ?? void 0;
144
+ return {
145
+ response,
146
+ ...contentType ? { contentType } : {}
147
+ };
148
+ }
149
+ function text(status, body, cache, extra = {}) {
150
+ return {
151
+ status,
152
+ headers: {
153
+ "content-type": "text/plain; charset=utf-8",
154
+ "cache-control": cache,
155
+ ...extra
156
+ },
157
+ body
158
+ };
159
+ }
160
+ //#endregion
161
+ //#region src/processors/AWSLambdaProcessor.ts
162
+ /**
163
+ * A processor as a Lambda behind a function URL — the CDN's origin for its
164
+ * pattern on AWS. The URL takes IAM auth and the CDN signs each request, so
165
+ * the function cannot be called around the cache.
166
+ */
167
+ var AWSLambdaProcessor = class {
168
+ serve;
169
+ constructor(processor, envParser = require_surfaceEnv.defaultEnvParser()) {
170
+ this.serve = processorServer([processor], envParser);
171
+ }
172
+ handler = async (event) => {
173
+ const response = await this.serve({
174
+ method: event.requestContext.http.method,
175
+ path: event.rawPath
176
+ });
177
+ if (!response) return {
178
+ statusCode: 404,
179
+ headers: { "cache-control": "public, max-age=60" },
180
+ body: "",
181
+ isBase64Encoded: false
182
+ };
183
+ const body = response.body ?? "";
184
+ return {
185
+ statusCode: response.status,
186
+ headers: response.headers,
187
+ body: typeof body === "string" ? body : Buffer.from(body).toString("base64"),
188
+ isBase64Encoded: typeof body !== "string"
189
+ };
190
+ };
191
+ };
192
+ //#endregion
193
+ exports.AWSLambdaProcessor = AWSLambdaProcessor;
194
+ Object.defineProperty(exports, "DERIVED_PREFIX", {
195
+ enumerable: true,
196
+ get: function() {
197
+ return _geekmidas_manifest.DERIVED_PREFIX;
198
+ }
199
+ });
200
+ exports.Processor = require_pattern.Processor;
201
+ exports.ProcessorBuilder = require_pattern.ProcessorBuilder;
202
+ exports.ProcessorNativeInvalid = require_pattern.ProcessorNativeInvalid;
203
+ exports.ProcessorParamMissing = require_pattern.ProcessorParamMissing;
204
+ exports.ProcessorPatternInvalid = require_pattern.ProcessorPatternInvalid;
205
+ exports.ProcessorSourceMissing = ProcessorSourceMissing;
206
+ exports.cacheControl = cacheControl;
207
+ exports.derivedKey = derivedKey;
208
+ exports.fillPattern = require_pattern.fillPattern;
209
+ exports.handleProcessorRequest = handleProcessorRequest;
210
+ exports.matchPattern = require_pattern.matchPattern;
211
+ exports.parsePattern = require_pattern.parsePattern;
212
+ exports.processorServer = processorServer;
213
+
214
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["DERIVED_PREFIX","fillPattern","matchPattern","runWithRequestContext","defaultEnvParser","ServiceDiscovery","defaultEnvParser"],"sources":["../../src/processors/runProcessor.ts","../../src/processors/AWSLambdaProcessor.ts"],"sourcesContent":["import type { EnvironmentParser } from '@geekmidas/envkit';\nimport type { Logger } from '@geekmidas/logger';\nimport { runWithRequestContext, ServiceDiscovery } from '@geekmidas/services';\nimport type { StorageClient } from '@geekmidas/storage';\nimport { defaultEnvParser } from '../endpoints/surfaceEnv';\nimport {\n\tDERIVED_PREFIX,\n\ttype Processor,\n\ttype ProcessorCache,\n\ttype SourceObject,\n} from './Processor';\nimport { fillPattern, matchPattern } from './pattern';\n\n/** What a processor answers, for whichever server or function carries it. */\nexport interface ProcessorResponse {\n\tstatus: number;\n\theaders: Record<string, string>;\n\tbody?: Uint8Array | string;\n}\n\n/** The object a request addressed is not in the bucket. */\nexport class ProcessorSourceMissing extends Error {\n\tconstructor(readonly key: string) {\n\t\tsuper(`'${key}' is not in the bucket, so there is nothing to process.`);\n\t\tthis.name = 'ProcessorSourceMissing';\n\t}\n}\n\n/** What a refusal or a miss may be kept for: long enough to absorb a burst. */\nconst SHORT = 'public, max-age=60';\n\n/** The header a response carries, by how long it may be kept. */\nexport function cacheControl(cache: ProcessorCache | undefined): string {\n\tif (cache === 'immutable') return 'public, max-age=31536000, immutable';\n\tif (cache === 'none') return 'no-store';\n\treturn `public, max-age=${cache?.maxAge ?? 3600}`;\n}\n\n/** Where a processor keeps the derivative for one request. */\nexport function derivedKey(\n\tprocessor: Processor<string, any, any, any>,\n\tparams: Readonly<Record<string, string>>,\n\tkey: string,\n): string {\n\treturn `${DERIVED_PREFIX}${fillPattern(processor.parsed, params, key).slice(1)}`;\n}\n\nexport interface ProcessorRequestOptions {\n\tserviceDiscovery: ServiceDiscovery<any>;\n\t/** How the bucket is read through a presigned address. */\n\tfetch?: typeof fetch;\n}\n\n/**\n * Answer one request with the first processor whose pattern matches it, or\n * `undefined` when none does.\n *\n * In order: the parameters are parsed by the processor's schema (400 when it\n * refuses them); the key must be one of the file server's open paths (404\n * otherwise, as an unsigned read of it would be); a derivative already in the\n * bucket is answered without running anything; and only then is the handler\n * run, its `immutable` result written through for next time.\n */\nexport async function handleProcessorRequest(\n\tprocessors: readonly Processor<string, any, any, any>[],\n\trequest: { method: string; path: string },\n\toptions: ProcessorRequestOptions,\n): Promise<ProcessorResponse | undefined> {\n\tconst method = request.method.toUpperCase();\n\n\tfor (const processor of processors) {\n\t\tconst match = matchPattern(processor.parsed, request.path);\n\t\tif (!match) continue;\n\n\t\tif (method !== 'GET' && method !== 'HEAD') {\n\t\t\treturn text(405, 'Method Not Allowed', 'no-store', {\n\t\t\t\tallow: 'GET, HEAD',\n\t\t\t});\n\t\t}\n\n\t\treturn runWithRequestContext(\n\t\t\t{\n\t\t\t\tlogger: processor.logger,\n\t\t\t\trequestId: `processor-${Date.now()}`,\n\t\t\t\tstartTime: Date.now(),\n\t\t\t\toperation: `processor ${processor.pattern}`,\n\t\t\t},\n\t\t\t() => run(processor, match, options),\n\t\t);\n\t}\n\n\treturn undefined;\n}\n\n/**\n * A request handler for a set of processors — what a generated entry serves\n * — with its services discovered from the default environment parser: the\n * process's environment and the credentials `gkm` injected.\n */\nexport function processorServer(\n\tprocessors: readonly Processor<string, any, any, any>[],\n\tenvParser: EnvironmentParser<{}> = defaultEnvParser(),\n): (request: {\n\tmethod: string;\n\tpath: string;\n}) => Promise<ProcessorResponse | undefined> {\n\tconst serviceDiscovery = ServiceDiscovery.getInstance(envParser);\n\treturn (request) =>\n\t\thandleProcessorRequest(processors, request, { serviceDiscovery });\n}\n\nasync function run(\n\tprocessor: Processor<string, any, any, any>,\n\tmatch: { params: Record<string, string>; key: string },\n\toptions: ProcessorRequestOptions,\n): Promise<ProcessorResponse> {\n\tconst logger = processor.logger as Logger;\n\tconst fetcher = options.fetch ?? fetch;\n\tconst { key } = match;\n\n\tconst schema = processor.options.paramsSchema;\n\tlet params: unknown = match.params;\n\tif (schema) {\n\t\tconst parsed = await schema['~standard'].validate(match.params);\n\t\tif (parsed.issues) return text(400, 'Bad Request', SHORT);\n\t\tparams = parsed.value;\n\t}\n\n\t// A derivative is never itself a source, and a private object is never\n\t// processed: a processor serves exactly what an unsigned read would.\n\tif (key.startsWith(DERIVED_PREFIX) || !processor.options.serves(key)) {\n\t\treturn text(404, 'Not Found', SHORT);\n\t}\n\n\tconst services: Record<string, unknown> =\n\t\tawait options.serviceDiscovery.register(processor.services);\n\tconst storage = services[\n\t\tprocessor.options.origin.serviceName\n\t] as StorageClient;\n\n\tconst derived = derivedKey(processor, match.params, key);\n\tconst kept = await read(storage, derived, fetcher);\n\tif (kept) {\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\theaders: {\n\t\t\t\t'content-type': kept.contentType ?? 'application/octet-stream',\n\t\t\t\t'cache-control': cacheControl('immutable'),\n\t\t\t\t'x-gkm-processor': 'kept',\n\t\t\t},\n\t\t\tbody: new Uint8Array(await kept.response.arrayBuffer()),\n\t\t};\n\t}\n\n\tlet source: Response | undefined;\n\tconst load = async (): Promise<Response> => {\n\t\tif (source) return source;\n\t\tconst found = await read(storage, key, fetcher);\n\t\tif (!found) throw new ProcessorSourceMissing(key);\n\t\tsource = found.response;\n\t\treturn source;\n\t};\n\tconst object: SourceObject = {\n\t\tkey,\n\t\tbytes: async () => new Uint8Array(await (await load()).arrayBuffer()),\n\t\tstream: async () => {\n\t\t\tconst body = (await load()).body;\n\t\t\tif (!body) throw new ProcessorSourceMissing(key);\n\t\t\treturn body;\n\t\t},\n\t\tcontentType: async () =>\n\t\t\t(await load()).headers.get('content-type') ?? undefined,\n\t};\n\n\tlet result: Awaited<ReturnType<typeof processor.handler>>;\n\ttry {\n\t\tresult = await processor.handler({\n\t\t\tparams,\n\t\t\tkey,\n\t\t\tobject,\n\t\t\tlogger,\n\t\t\tservices,\n\t\t} as never);\n\t} catch (error) {\n\t\tif (error instanceof ProcessorSourceMissing) {\n\t\t\treturn text(404, 'Not Found', SHORT);\n\t\t}\n\t\tlogger.error({ err: error, key }, 'Processor failed');\n\t\treturn text(500, 'Internal Server Error', 'no-store');\n\t}\n\n\tconst body =\n\t\ttypeof result.body === 'string'\n\t\t\t? new TextEncoder().encode(result.body)\n\t\t\t: result.body;\n\n\t// Kept only when it can never change: anything else would be served from\n\t// the bucket long after its handler would have answered differently.\n\tif (result.cache === 'immutable') {\n\t\tawait storage\n\t\t\t.upload(derived, Buffer.from(body), result.contentType)\n\t\t\t.catch((error: unknown) =>\n\t\t\t\tlogger.warn({ err: error, key: derived }, 'Could not keep derivative'),\n\t\t\t);\n\t}\n\n\treturn {\n\t\tstatus: 200,\n\t\theaders: {\n\t\t\t'content-type': result.contentType,\n\t\t\t'cache-control': cacheControl(result.cache),\n\t\t\t'x-gkm-processor': 'made',\n\t\t},\n\t\tbody,\n\t};\n}\n\n/** An object through a presigned address, or nothing when it is not there. */\nasync function read(\n\tstorage: StorageClient,\n\tkey: string,\n\tfetcher: typeof fetch,\n): Promise<{ response: Response; contentType?: string } | undefined> {\n\tconst url = await storage.getDownloadURL({ path: key });\n\tconst response = await fetcher(url);\n\tif (!response.ok) {\n\t\tawait response.body?.cancel().catch(() => undefined);\n\t\treturn undefined;\n\t}\n\tconst contentType = response.headers.get('content-type') ?? undefined;\n\treturn { response, ...(contentType ? { contentType } : {}) };\n}\n\nfunction text(\n\tstatus: number,\n\tbody: string,\n\tcache: string,\n\textra: Record<string, string> = {},\n): ProcessorResponse {\n\treturn {\n\t\tstatus,\n\t\theaders: {\n\t\t\t'content-type': 'text/plain; charset=utf-8',\n\t\t\t'cache-control': cache,\n\t\t\t...extra,\n\t\t},\n\t\tbody,\n\t};\n}\n","import type { EnvironmentParser } from '@geekmidas/envkit';\nimport { defaultEnvParser } from '../endpoints/surfaceEnv';\nimport type { Processor } from './Processor';\nimport { processorServer } from './runProcessor';\n\n/** The parts of a Lambda function URL event a processor reads. */\nexport interface FunctionUrlEvent {\n\trawPath: string;\n\trequestContext: { http: { method: string } };\n}\n\n/** What a function URL answers with. */\nexport interface FunctionUrlResult {\n\tstatusCode: number;\n\theaders: Record<string, string>;\n\tbody: string;\n\tisBase64Encoded: boolean;\n}\n\n/**\n * A processor as a Lambda behind a function URL — the CDN's origin for its\n * pattern on AWS. The URL takes IAM auth and the CDN signs each request, so\n * the function cannot be called around the cache.\n */\nexport class AWSLambdaProcessor {\n\tprivate readonly serve: ReturnType<typeof processorServer>;\n\n\tconstructor(\n\t\tprocessor: Processor<string, any, any, any>,\n\t\tenvParser: EnvironmentParser<{}> = defaultEnvParser(),\n\t) {\n\t\tthis.serve = processorServer([processor], envParser);\n\t}\n\n\thandler = async (event: FunctionUrlEvent): Promise<FunctionUrlResult> => {\n\t\tconst response = await this.serve({\n\t\t\tmethod: event.requestContext.http.method,\n\t\t\tpath: event.rawPath,\n\t\t});\n\t\tif (!response) {\n\t\t\treturn {\n\t\t\t\tstatusCode: 404,\n\t\t\t\theaders: { 'cache-control': 'public, max-age=60' },\n\t\t\t\tbody: '',\n\t\t\t\tisBase64Encoded: false,\n\t\t\t};\n\t\t}\n\t\tconst body = response.body ?? '';\n\t\treturn {\n\t\t\tstatusCode: response.status,\n\t\t\theaders: response.headers,\n\t\t\tbody:\n\t\t\t\ttypeof body === 'string' ? body : Buffer.from(body).toString('base64'),\n\t\t\tisBase64Encoded: typeof body !== 'string',\n\t\t};\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { _ as parsePattern, a as ProcessorCache, c as ProcessorParams, d as ParsedPattern, f as PatternParams, g as matchPattern, h as fillPattern, i as Processor, l as ProcessorResult, m as ProcessorPatternInvalid, n as ProcessorNativeInvalid, o as ProcessorContext, p as ProcessorParamMissing, r as DERIVED_PREFIX, s as ProcessorHandler, t as ProcessorBuilder, u as SourceObject } from "../ProcessorBuilder-C62bIOwj.cjs";
2
+ import { EnvironmentParser } from "@geekmidas/envkit";
3
+ import { ServiceDiscovery } from "@geekmidas/services";
4
+ //#region src/processors/AWSLambdaProcessor.d.ts
5
+ /** The parts of a Lambda function URL event a processor reads. */
6
+ interface FunctionUrlEvent {
7
+ rawPath: string;
8
+ requestContext: {
9
+ http: {
10
+ method: string;
11
+ };
12
+ };
13
+ }
14
+ /** What a function URL answers with. */
15
+ interface FunctionUrlResult {
16
+ statusCode: number;
17
+ headers: Record<string, string>;
18
+ body: string;
19
+ isBase64Encoded: boolean;
20
+ }
21
+ /**
22
+ * A processor as a Lambda behind a function URL — the CDN's origin for its
23
+ * pattern on AWS. The URL takes IAM auth and the CDN signs each request, so
24
+ * the function cannot be called around the cache.
25
+ */
26
+ export declare class AWSLambdaProcessor {
27
+ private readonly serve;
28
+ constructor(processor: Processor<string, any, any, any>, envParser?: EnvironmentParser<{}>);
29
+ handler: (event: FunctionUrlEvent) => Promise<FunctionUrlResult>;
30
+ }
31
+ //#endregion
32
+ //#region src/processors/runProcessor.d.ts
33
+ /** What a processor answers, for whichever server or function carries it. */
34
+ interface ProcessorResponse {
35
+ status: number;
36
+ headers: Record<string, string>;
37
+ body?: Uint8Array | string;
38
+ }
39
+ /** The object a request addressed is not in the bucket. */
40
+ export declare class ProcessorSourceMissing extends Error {
41
+ readonly key: string;
42
+ constructor(key: string);
43
+ }
44
+ /** The header a response carries, by how long it may be kept. */
45
+ export declare function cacheControl(cache: ProcessorCache | undefined): string;
46
+ /** Where a processor keeps the derivative for one request. */
47
+ export declare function derivedKey(processor: Processor<string, any, any, any>, params: Readonly<Record<string, string>>, key: string): string;
48
+ interface ProcessorRequestOptions {
49
+ serviceDiscovery: ServiceDiscovery<any>;
50
+ /** How the bucket is read through a presigned address. */
51
+ fetch?: typeof fetch;
52
+ }
53
+ /**
54
+ * Answer one request with the first processor whose pattern matches it, or
55
+ * `undefined` when none does.
56
+ *
57
+ * In order: the parameters are parsed by the processor's schema (400 when it
58
+ * refuses them); the key must be one of the file server's open paths (404
59
+ * otherwise, as an unsigned read of it would be); a derivative already in the
60
+ * bucket is answered without running anything; and only then is the handler
61
+ * run, its `immutable` result written through for next time.
62
+ */
63
+ export declare function handleProcessorRequest(processors: readonly Processor<string, any, any, any>[], request: {
64
+ method: string;
65
+ path: string;
66
+ }, options: ProcessorRequestOptions): Promise<ProcessorResponse | undefined>;
67
+ /**
68
+ * A request handler for a set of processors — what a generated entry serves
69
+ * — with its services discovered from the default environment parser: the
70
+ * process's environment and the credentials `gkm` injected.
71
+ */
72
+ export declare function processorServer(processors: readonly Processor<string, any, any, any>[], envParser?: EnvironmentParser<{}>): (request: {
73
+ method: string;
74
+ path: string;
75
+ }) => Promise<ProcessorResponse | undefined>;
76
+ //#endregion
77
+ export { DERIVED_PREFIX, type ParsedPattern, type PatternParams, Processor, ProcessorBuilder, type ProcessorCache, type ProcessorContext, type ProcessorHandler, ProcessorNativeInvalid, ProcessorParamMissing, type ProcessorParams, ProcessorPatternInvalid, type ProcessorRequestOptions, type ProcessorResponse, type ProcessorResult, type SourceObject, fillPattern, matchPattern, parsePattern };
78
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/processors/AWSLambdaProcessor.ts","../../src/processors/runProcessor.ts"],"mappings":";;;;;UAMiB;EAChB;EACA;IAAkB;MAAQ;;;;;UAIV;EAChB;EACA,SAAS;EACT;EACA;;;;;;;qBAQY;mBACK;EAEjB,YACC,WAAW,kCACX,YAAW;EAKZ,UAAO,OAAiB,qBAAmB,QAAQ;;;;;UCpBnC;EAChB;EACA,SAAS;EACT,OAAO;;;qBAIK,+BAA+B;WACtB;EAArB,YAAqB;;;wBAUN,aAAa,OAAO;;wBAOpB,WACf,WAAW,kCACX,QAAQ,SAAS,yBACjB;UAKgB;EAChB,kBAAkB;;EAElB,eAAe;;;;;;;;;;;;wBAaM,uBACrB,qBAAqB,oCACrB;EAAW;EAAgB;GAC3B,SAAS,0BACP,QAAQ;;;;;;wBAgCK,gBACf,qBAAqB,oCACrB,YAAW,yBACR;EACH;EACA;MACK,QAAQ"}
@@ -0,0 +1,78 @@
1
+ import { _ as parsePattern, a as ProcessorCache, c as ProcessorParams, d as ParsedPattern, f as PatternParams, g as matchPattern, h as fillPattern, i as Processor, l as ProcessorResult, m as ProcessorPatternInvalid, n as ProcessorNativeInvalid, o as ProcessorContext, p as ProcessorParamMissing, r as DERIVED_PREFIX, s as ProcessorHandler, t as ProcessorBuilder, u as SourceObject } from "../ProcessorBuilder-B2_stA8f.mjs";
2
+ import { ServiceDiscovery } from "@geekmidas/services";
3
+ import { EnvironmentParser } from "@geekmidas/envkit";
4
+ //#region src/processors/AWSLambdaProcessor.d.ts
5
+ /** The parts of a Lambda function URL event a processor reads. */
6
+ interface FunctionUrlEvent {
7
+ rawPath: string;
8
+ requestContext: {
9
+ http: {
10
+ method: string;
11
+ };
12
+ };
13
+ }
14
+ /** What a function URL answers with. */
15
+ interface FunctionUrlResult {
16
+ statusCode: number;
17
+ headers: Record<string, string>;
18
+ body: string;
19
+ isBase64Encoded: boolean;
20
+ }
21
+ /**
22
+ * A processor as a Lambda behind a function URL — the CDN's origin for its
23
+ * pattern on AWS. The URL takes IAM auth and the CDN signs each request, so
24
+ * the function cannot be called around the cache.
25
+ */
26
+ export declare class AWSLambdaProcessor {
27
+ private readonly serve;
28
+ constructor(processor: Processor<string, any, any, any>, envParser?: EnvironmentParser<{}>);
29
+ handler: (event: FunctionUrlEvent) => Promise<FunctionUrlResult>;
30
+ }
31
+ //#endregion
32
+ //#region src/processors/runProcessor.d.ts
33
+ /** What a processor answers, for whichever server or function carries it. */
34
+ interface ProcessorResponse {
35
+ status: number;
36
+ headers: Record<string, string>;
37
+ body?: Uint8Array | string;
38
+ }
39
+ /** The object a request addressed is not in the bucket. */
40
+ export declare class ProcessorSourceMissing extends Error {
41
+ readonly key: string;
42
+ constructor(key: string);
43
+ }
44
+ /** The header a response carries, by how long it may be kept. */
45
+ export declare function cacheControl(cache: ProcessorCache | undefined): string;
46
+ /** Where a processor keeps the derivative for one request. */
47
+ export declare function derivedKey(processor: Processor<string, any, any, any>, params: Readonly<Record<string, string>>, key: string): string;
48
+ interface ProcessorRequestOptions {
49
+ serviceDiscovery: ServiceDiscovery<any>;
50
+ /** How the bucket is read through a presigned address. */
51
+ fetch?: typeof fetch;
52
+ }
53
+ /**
54
+ * Answer one request with the first processor whose pattern matches it, or
55
+ * `undefined` when none does.
56
+ *
57
+ * In order: the parameters are parsed by the processor's schema (400 when it
58
+ * refuses them); the key must be one of the file server's open paths (404
59
+ * otherwise, as an unsigned read of it would be); a derivative already in the
60
+ * bucket is answered without running anything; and only then is the handler
61
+ * run, its `immutable` result written through for next time.
62
+ */
63
+ export declare function handleProcessorRequest(processors: readonly Processor<string, any, any, any>[], request: {
64
+ method: string;
65
+ path: string;
66
+ }, options: ProcessorRequestOptions): Promise<ProcessorResponse | undefined>;
67
+ /**
68
+ * A request handler for a set of processors — what a generated entry serves
69
+ * — with its services discovered from the default environment parser: the
70
+ * process's environment and the credentials `gkm` injected.
71
+ */
72
+ export declare function processorServer(processors: readonly Processor<string, any, any, any>[], envParser?: EnvironmentParser<{}>): (request: {
73
+ method: string;
74
+ path: string;
75
+ }) => Promise<ProcessorResponse | undefined>;
76
+ //#endregion
77
+ export { DERIVED_PREFIX, type ParsedPattern, type PatternParams, Processor, ProcessorBuilder, type ProcessorCache, type ProcessorContext, type ProcessorHandler, ProcessorNativeInvalid, ProcessorParamMissing, type ProcessorParams, ProcessorPatternInvalid, type ProcessorRequestOptions, type ProcessorResponse, type ProcessorResult, type SourceObject, fillPattern, matchPattern, parsePattern };
78
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/processors/AWSLambdaProcessor.ts","../../src/processors/runProcessor.ts"],"mappings":";;;;;UAMiB;EAChB;EACA;IAAkB;MAAQ;;;;;UAIV;EAChB;EACA,SAAS;EACT;EACA;;;;;;;qBAQY;mBACK;EAEjB,YACC,WAAW,kCACX,YAAW;EAKZ,UAAO,OAAiB,qBAAmB,QAAQ;;;;;UCpBnC;EAChB;EACA,SAAS;EACT,OAAO;;;qBAIK,+BAA+B;WACtB;EAArB,YAAqB;;;wBAUN,aAAa,OAAO;;wBAOpB,WACf,WAAW,kCACX,QAAQ,SAAS,yBACjB;UAKgB;EAChB,kBAAkB;;EAElB,eAAe;;;;;;;;;;;;wBAaM,uBACrB,qBAAqB,oCACrB;EAAW;EAAgB;GAC3B,SAAS,0BACP,QAAQ;;;;;;wBAgCK,gBACf,qBAAqB,oCACrB,YAAW,yBACR;EACH;EACA;MACK,QAAQ"}
@@ -0,0 +1,193 @@
1
+ import { a as parsePattern, c as DERIVED_PREFIX, i as matchPattern, l as Processor, n as ProcessorPatternInvalid, o as ProcessorBuilder, r as fillPattern, s as ProcessorNativeInvalid, t as ProcessorParamMissing } from "../pattern-C1CEcglD.mjs";
2
+ import { t as defaultEnvParser } from "../surfaceEnv-wMT5QzgZ.mjs";
3
+ import { ServiceDiscovery, runWithRequestContext } from "@geekmidas/services";
4
+ //#region src/processors/runProcessor.ts
5
+ /** The object a request addressed is not in the bucket. */
6
+ var ProcessorSourceMissing = class extends Error {
7
+ key;
8
+ constructor(key) {
9
+ super(`'${key}' is not in the bucket, so there is nothing to process.`);
10
+ this.key = key;
11
+ this.name = "ProcessorSourceMissing";
12
+ }
13
+ };
14
+ /** What a refusal or a miss may be kept for: long enough to absorb a burst. */
15
+ const SHORT = "public, max-age=60";
16
+ /** The header a response carries, by how long it may be kept. */
17
+ function cacheControl(cache) {
18
+ if (cache === "immutable") return "public, max-age=31536000, immutable";
19
+ if (cache === "none") return "no-store";
20
+ return `public, max-age=${cache?.maxAge ?? 3600}`;
21
+ }
22
+ /** Where a processor keeps the derivative for one request. */
23
+ function derivedKey(processor, params, key) {
24
+ return `${DERIVED_PREFIX}${fillPattern(processor.parsed, params, key).slice(1)}`;
25
+ }
26
+ /**
27
+ * Answer one request with the first processor whose pattern matches it, or
28
+ * `undefined` when none does.
29
+ *
30
+ * In order: the parameters are parsed by the processor's schema (400 when it
31
+ * refuses them); the key must be one of the file server's open paths (404
32
+ * otherwise, as an unsigned read of it would be); a derivative already in the
33
+ * bucket is answered without running anything; and only then is the handler
34
+ * run, its `immutable` result written through for next time.
35
+ */
36
+ async function handleProcessorRequest(processors, request, options) {
37
+ const method = request.method.toUpperCase();
38
+ for (const processor of processors) {
39
+ const match = matchPattern(processor.parsed, request.path);
40
+ if (!match) continue;
41
+ if (method !== "GET" && method !== "HEAD") return text(405, "Method Not Allowed", "no-store", { allow: "GET, HEAD" });
42
+ return runWithRequestContext({
43
+ logger: processor.logger,
44
+ requestId: `processor-${Date.now()}`,
45
+ startTime: Date.now(),
46
+ operation: `processor ${processor.pattern}`
47
+ }, () => run(processor, match, options));
48
+ }
49
+ }
50
+ /**
51
+ * A request handler for a set of processors — what a generated entry serves
52
+ * — with its services discovered from the default environment parser: the
53
+ * process's environment and the credentials `gkm` injected.
54
+ */
55
+ function processorServer(processors, envParser = defaultEnvParser()) {
56
+ const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
57
+ return (request) => handleProcessorRequest(processors, request, { serviceDiscovery });
58
+ }
59
+ async function run(processor, match, options) {
60
+ const logger = processor.logger;
61
+ const fetcher = options.fetch ?? fetch;
62
+ const { key } = match;
63
+ const schema = processor.options.paramsSchema;
64
+ let params = match.params;
65
+ if (schema) {
66
+ const parsed = await schema["~standard"].validate(match.params);
67
+ if (parsed.issues) return text(400, "Bad Request", SHORT);
68
+ params = parsed.value;
69
+ }
70
+ if (key.startsWith(DERIVED_PREFIX) || !processor.options.serves(key)) return text(404, "Not Found", SHORT);
71
+ const services = await options.serviceDiscovery.register(processor.services);
72
+ const storage = services[processor.options.origin.serviceName];
73
+ const derived = derivedKey(processor, match.params, key);
74
+ const kept = await read(storage, derived, fetcher);
75
+ if (kept) return {
76
+ status: 200,
77
+ headers: {
78
+ "content-type": kept.contentType ?? "application/octet-stream",
79
+ "cache-control": cacheControl("immutable"),
80
+ "x-gkm-processor": "kept"
81
+ },
82
+ body: new Uint8Array(await kept.response.arrayBuffer())
83
+ };
84
+ let source;
85
+ const load = async () => {
86
+ if (source) return source;
87
+ const found = await read(storage, key, fetcher);
88
+ if (!found) throw new ProcessorSourceMissing(key);
89
+ source = found.response;
90
+ return source;
91
+ };
92
+ const object = {
93
+ key,
94
+ bytes: async () => new Uint8Array(await (await load()).arrayBuffer()),
95
+ stream: async () => {
96
+ const body = (await load()).body;
97
+ if (!body) throw new ProcessorSourceMissing(key);
98
+ return body;
99
+ },
100
+ contentType: async () => (await load()).headers.get("content-type") ?? void 0
101
+ };
102
+ let result;
103
+ try {
104
+ result = await processor.handler({
105
+ params,
106
+ key,
107
+ object,
108
+ logger,
109
+ services
110
+ });
111
+ } catch (error) {
112
+ if (error instanceof ProcessorSourceMissing) return text(404, "Not Found", SHORT);
113
+ logger.error({
114
+ err: error,
115
+ key
116
+ }, "Processor failed");
117
+ return text(500, "Internal Server Error", "no-store");
118
+ }
119
+ const body = typeof result.body === "string" ? new TextEncoder().encode(result.body) : result.body;
120
+ if (result.cache === "immutable") await storage.upload(derived, Buffer.from(body), result.contentType).catch((error) => logger.warn({
121
+ err: error,
122
+ key: derived
123
+ }, "Could not keep derivative"));
124
+ return {
125
+ status: 200,
126
+ headers: {
127
+ "content-type": result.contentType,
128
+ "cache-control": cacheControl(result.cache),
129
+ "x-gkm-processor": "made"
130
+ },
131
+ body
132
+ };
133
+ }
134
+ /** An object through a presigned address, or nothing when it is not there. */
135
+ async function read(storage, key, fetcher) {
136
+ const response = await fetcher(await storage.getDownloadURL({ path: key }));
137
+ if (!response.ok) {
138
+ await response.body?.cancel().catch(() => void 0);
139
+ return;
140
+ }
141
+ const contentType = response.headers.get("content-type") ?? void 0;
142
+ return {
143
+ response,
144
+ ...contentType ? { contentType } : {}
145
+ };
146
+ }
147
+ function text(status, body, cache, extra = {}) {
148
+ return {
149
+ status,
150
+ headers: {
151
+ "content-type": "text/plain; charset=utf-8",
152
+ "cache-control": cache,
153
+ ...extra
154
+ },
155
+ body
156
+ };
157
+ }
158
+ //#endregion
159
+ //#region src/processors/AWSLambdaProcessor.ts
160
+ /**
161
+ * A processor as a Lambda behind a function URL — the CDN's origin for its
162
+ * pattern on AWS. The URL takes IAM auth and the CDN signs each request, so
163
+ * the function cannot be called around the cache.
164
+ */
165
+ var AWSLambdaProcessor = class {
166
+ serve;
167
+ constructor(processor, envParser = defaultEnvParser()) {
168
+ this.serve = processorServer([processor], envParser);
169
+ }
170
+ handler = async (event) => {
171
+ const response = await this.serve({
172
+ method: event.requestContext.http.method,
173
+ path: event.rawPath
174
+ });
175
+ if (!response) return {
176
+ statusCode: 404,
177
+ headers: { "cache-control": "public, max-age=60" },
178
+ body: "",
179
+ isBase64Encoded: false
180
+ };
181
+ const body = response.body ?? "";
182
+ return {
183
+ statusCode: response.status,
184
+ headers: response.headers,
185
+ body: typeof body === "string" ? body : Buffer.from(body).toString("base64"),
186
+ isBase64Encoded: typeof body !== "string"
187
+ };
188
+ };
189
+ };
190
+ //#endregion
191
+ export { AWSLambdaProcessor, DERIVED_PREFIX, Processor, ProcessorBuilder, ProcessorNativeInvalid, ProcessorParamMissing, ProcessorPatternInvalid, ProcessorSourceMissing, cacheControl, derivedKey, fillPattern, handleProcessorRequest, matchPattern, parsePattern, processorServer };
192
+
193
+ //# sourceMappingURL=index.mjs.map