@voyant-travel/hono 0.109.1
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/LICENSE +201 -0
- package/README.md +58 -0
- package/dist/app-workflows.d.ts +31 -0
- package/dist/app-workflows.d.ts.map +1 -0
- package/dist/app-workflows.js +110 -0
- package/dist/app.d.ts +45 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +403 -0
- package/dist/auth/crypto.d.ts +16 -0
- package/dist/auth/crypto.d.ts.map +1 -0
- package/dist/auth/crypto.js +66 -0
- package/dist/auth/index.d.ts +5 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/require-user.d.ts +3 -0
- package/dist/auth/require-user.d.ts.map +1 -0
- package/dist/auth/require-user.js +8 -0
- package/dist/auth/session-jwt.d.ts +7 -0
- package/dist/auth/session-jwt.d.ts.map +1 -0
- package/dist/auth/session-jwt.js +23 -0
- package/dist/composition.d.ts +67 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +46 -0
- package/dist/document-download.d.ts +30 -0
- package/dist/document-download.d.ts.map +1 -0
- package/dist/document-download.js +102 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/lib/db-selector.d.ts +24 -0
- package/dist/lib/db-selector.d.ts.map +1 -0
- package/dist/lib/db-selector.js +28 -0
- package/dist/lib/execution-ctx.d.ts +16 -0
- package/dist/lib/execution-ctx.d.ts.map +1 -0
- package/dist/lib/execution-ctx.js +16 -0
- package/dist/lib/public-paths.d.ts +19 -0
- package/dist/lib/public-paths.d.ts.map +1 -0
- package/dist/lib/public-paths.js +27 -0
- package/dist/lib/request-event-bus.d.ts +21 -0
- package/dist/lib/request-event-bus.d.ts.map +1 -0
- package/dist/lib/request-event-bus.js +43 -0
- package/dist/middleware/auth.d.ts +10 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +280 -0
- package/dist/middleware/body-size.d.ts +7 -0
- package/dist/middleware/body-size.d.ts.map +1 -0
- package/dist/middleware/body-size.js +20 -0
- package/dist/middleware/cors.d.ts +6 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +94 -0
- package/dist/middleware/db.d.ts +43 -0
- package/dist/middleware/db.d.ts.map +1 -0
- package/dist/middleware/db.js +78 -0
- package/dist/middleware/error-boundary.d.ts +5 -0
- package/dist/middleware/error-boundary.d.ts.map +1 -0
- package/dist/middleware/error-boundary.js +76 -0
- package/dist/middleware/idempotency-key.d.ts +97 -0
- package/dist/middleware/idempotency-key.d.ts.map +1 -0
- package/dist/middleware/idempotency-key.js +235 -0
- package/dist/middleware/index.d.ts +14 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +13 -0
- package/dist/middleware/logger.d.ts +5 -0
- package/dist/middleware/logger.d.ts.map +1 -0
- package/dist/middleware/logger.js +27 -0
- package/dist/middleware/metrics.d.ts +55 -0
- package/dist/middleware/metrics.d.ts.map +1 -0
- package/dist/middleware/metrics.js +94 -0
- package/dist/middleware/public-cache.d.ts +44 -0
- package/dist/middleware/public-cache.d.ts.map +1 -0
- package/dist/middleware/public-cache.js +205 -0
- package/dist/middleware/rate-limit.d.ts +214 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +240 -0
- package/dist/middleware/request-db.d.ts +42 -0
- package/dist/middleware/request-db.d.ts.map +1 -0
- package/dist/middleware/request-db.js +62 -0
- package/dist/middleware/require-actor.d.ts +28 -0
- package/dist/middleware/require-actor.d.ts.map +1 -0
- package/dist/middleware/require-actor.js +89 -0
- package/dist/middleware/require-permission.d.ts +9 -0
- package/dist/middleware/require-permission.d.ts.map +1 -0
- package/dist/middleware/require-permission.js +62 -0
- package/dist/middleware/security-headers.d.ts +10 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +19 -0
- package/dist/module.d.ts +41 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +1 -0
- package/dist/plugin.d.ts +66 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +37 -0
- package/dist/public-capability.d.ts +46 -0
- package/dist/public-capability.d.ts.map +1 -0
- package/dist/public-capability.js +140 -0
- package/dist/public-document-delivery.d.ts +111 -0
- package/dist/public-document-delivery.d.ts.map +1 -0
- package/dist/public-document-delivery.js +234 -0
- package/dist/types.d.ts +318 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +29 -0
- package/dist/validation.d.ts +36 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +106 -0
- package/package.json +156 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function normalizeEntry(entry) {
|
|
2
|
+
if (typeof entry === "string")
|
|
3
|
+
return { resolve: entry, options: {} };
|
|
4
|
+
return { resolve: entry.resolve, options: entry.options ?? {} };
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Derive the `createApp({ modules, extensions })` arrays from a manifest by
|
|
8
|
+
* looking each entry up in the registry, **preserving manifest order** (mount
|
|
9
|
+
* + hook-registration order is significant). Throws if the manifest lists an
|
|
10
|
+
* entry the registry has no factory for — so "added to the manifest but not
|
|
11
|
+
* wired" fails loudly at boot rather than silently dropping a module.
|
|
12
|
+
*/
|
|
13
|
+
export function composeFromManifest(manifest, registry, capabilities) {
|
|
14
|
+
const modules = (manifest.modules ?? []).flatMap((entry) => {
|
|
15
|
+
const { resolve, options } = normalizeEntry(entry);
|
|
16
|
+
const factory = registry.modules[resolve];
|
|
17
|
+
if (!factory) {
|
|
18
|
+
throw new Error(`composeFromManifest: no module factory registered for "${resolve}". ` +
|
|
19
|
+
"Add it to the composition registry, or remove it from voyant.config modules.");
|
|
20
|
+
}
|
|
21
|
+
return factory({ capabilities, options });
|
|
22
|
+
});
|
|
23
|
+
const extensions = (manifest.extensions ?? []).map((entry) => {
|
|
24
|
+
const { resolve, options } = normalizeEntry(entry);
|
|
25
|
+
const factory = registry.extensions?.[resolve];
|
|
26
|
+
if (!factory) {
|
|
27
|
+
throw new Error(`composeFromManifest: no extension factory registered for "${resolve}". ` +
|
|
28
|
+
"Add it to the composition registry, or remove it from voyant.config extensions.");
|
|
29
|
+
}
|
|
30
|
+
return factory({ capabilities, options });
|
|
31
|
+
});
|
|
32
|
+
return { modules, extensions };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pure parity check between a manifest's entries and a registry's keys, for
|
|
36
|
+
* tooling (`voyant db doctor`). Reports manifest entries with no factory and
|
|
37
|
+
* factories the manifest never references.
|
|
38
|
+
*/
|
|
39
|
+
export function diffManifestRegistry(manifestEntries, registryKeys) {
|
|
40
|
+
const manifest = new Set(manifestEntries.map((e) => normalizeEntry(e).resolve));
|
|
41
|
+
const registry = new Set(registryKeys);
|
|
42
|
+
return {
|
|
43
|
+
missingFactories: [...manifest].filter((name) => !registry.has(name)).sort(),
|
|
44
|
+
orphanFactories: [...registry].filter((name) => !manifest.has(name)).sort(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface DocumentDownloadEnvelope {
|
|
2
|
+
url: string;
|
|
3
|
+
expiresAt: string | null;
|
|
4
|
+
filename: string | null;
|
|
5
|
+
}
|
|
6
|
+
export type DocumentDownloadResolution = {
|
|
7
|
+
status: "ready";
|
|
8
|
+
download: DocumentDownloadEnvelope;
|
|
9
|
+
} | {
|
|
10
|
+
status: "resolver_not_configured";
|
|
11
|
+
} | {
|
|
12
|
+
status: "not_available";
|
|
13
|
+
};
|
|
14
|
+
export type DocumentDownloadResolverResult = string | {
|
|
15
|
+
url: string;
|
|
16
|
+
expiresAt?: string | null;
|
|
17
|
+
filename?: string | null;
|
|
18
|
+
} | null | undefined;
|
|
19
|
+
export type DocumentDownloadResolver<TBindings = unknown> = (bindings: TBindings, storageKey: string) => Promise<DocumentDownloadResolverResult> | DocumentDownloadResolverResult;
|
|
20
|
+
export interface StoredDocumentReference {
|
|
21
|
+
storageKey?: string | null;
|
|
22
|
+
metadata?: unknown;
|
|
23
|
+
filename?: string | null;
|
|
24
|
+
name?: string | null;
|
|
25
|
+
}
|
|
26
|
+
export declare function resolveStoredDocumentDownload<TBindings = unknown>(reference: StoredDocumentReference, options: {
|
|
27
|
+
bindings: TBindings;
|
|
28
|
+
resolveDocumentDownloadUrl?: DocumentDownloadResolver<TBindings>;
|
|
29
|
+
}): Promise<DocumentDownloadResolution>;
|
|
30
|
+
//# sourceMappingURL=document-download.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-download.d.ts","sourceRoot":"","sources":["../src/document-download.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,wBAAwB,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,yBAAyB,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,CAAA;AAE/B,MAAM,MAAM,8BAA8B,GACtC,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,GACD,IAAI,GACJ,SAAS,CAAA;AAEb,MAAM,MAAM,wBAAwB,CAAC,SAAS,GAAG,OAAO,IAAI,CAC1D,QAAQ,EAAE,SAAS,EACnB,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,8BAA8B,CAAC,GAAG,8BAA8B,CAAA;AAE7E,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAwGD,wBAAsB,6BAA6B,CAAC,SAAS,GAAG,OAAO,EACrE,SAAS,EAAE,uBAAuB,EAClC,OAAO,EAAE;IACP,QAAQ,EAAE,SAAS,CAAA;IACnB,0BAA0B,CAAC,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAA;CACjE,GACA,OAAO,CAAC,0BAA0B,CAAC,CA2BrC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
function getMetadataRecord(metadata) {
|
|
2
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
5
|
+
return metadata;
|
|
6
|
+
}
|
|
7
|
+
function maybeString(value) {
|
|
8
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
9
|
+
}
|
|
10
|
+
function maybeUrl(value) {
|
|
11
|
+
const candidate = maybeString(value);
|
|
12
|
+
return candidate && /^https?:\/\//i.test(candidate) ? candidate : null;
|
|
13
|
+
}
|
|
14
|
+
function maybeIsoString(value) {
|
|
15
|
+
return maybeString(value);
|
|
16
|
+
}
|
|
17
|
+
function filenameFromStorageKey(storageKey) {
|
|
18
|
+
const normalized = maybeString(storageKey);
|
|
19
|
+
if (!normalized) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return normalized.split("/").filter(Boolean).at(-1) ?? null;
|
|
23
|
+
}
|
|
24
|
+
function getReferenceFilename(reference) {
|
|
25
|
+
const record = getMetadataRecord(reference.metadata);
|
|
26
|
+
return (maybeString(reference.filename) ??
|
|
27
|
+
maybeString(reference.name) ??
|
|
28
|
+
maybeString(record?.filename) ??
|
|
29
|
+
maybeString(record?.fileName) ??
|
|
30
|
+
maybeString(record?.name) ??
|
|
31
|
+
maybeString(record?.originalName) ??
|
|
32
|
+
filenameFromStorageKey(reference.storageKey));
|
|
33
|
+
}
|
|
34
|
+
function getMetadataExpiresAt(metadata) {
|
|
35
|
+
const record = getMetadataRecord(metadata);
|
|
36
|
+
return maybeIsoString(record?.expiresAt) ?? maybeIsoString(record?.expires_at);
|
|
37
|
+
}
|
|
38
|
+
function getFallbackDownload(reference) {
|
|
39
|
+
const record = getMetadataRecord(reference.metadata);
|
|
40
|
+
if (!record) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const url = maybeUrl(record.url) ?? maybeUrl(record.downloadUrl);
|
|
44
|
+
if (!url) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
url,
|
|
49
|
+
expiresAt: getMetadataExpiresAt(record),
|
|
50
|
+
filename: getReferenceFilename(reference),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function normalizeResolverDownload(value, reference) {
|
|
54
|
+
if (typeof value === "string") {
|
|
55
|
+
const url = maybeUrl(value);
|
|
56
|
+
if (!url) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
url,
|
|
61
|
+
expiresAt: getMetadataExpiresAt(reference.metadata),
|
|
62
|
+
filename: getReferenceFilename(reference),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const url = maybeUrl(value.url);
|
|
69
|
+
if (!url) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
url,
|
|
74
|
+
expiresAt: value.expiresAt === undefined
|
|
75
|
+
? getMetadataExpiresAt(reference.metadata)
|
|
76
|
+
: maybeIsoString(value.expiresAt),
|
|
77
|
+
filename: maybeString(value.filename) ?? getReferenceFilename(reference),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export async function resolveStoredDocumentDownload(reference, options) {
|
|
81
|
+
let needsResolver = false;
|
|
82
|
+
if (reference.storageKey) {
|
|
83
|
+
if (!options.resolveDocumentDownloadUrl) {
|
|
84
|
+
needsResolver = true;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const resolved = await options.resolveDocumentDownloadUrl(options.bindings, reference.storageKey);
|
|
88
|
+
const download = normalizeResolverDownload(resolved, reference);
|
|
89
|
+
if (download) {
|
|
90
|
+
return { status: "ready", download };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const fallback = getFallbackDownload(reference);
|
|
95
|
+
if (fallback) {
|
|
96
|
+
return { status: "ready", download: fallback };
|
|
97
|
+
}
|
|
98
|
+
if (needsResolver) {
|
|
99
|
+
return { status: "resolver_not_configured" };
|
|
100
|
+
}
|
|
101
|
+
return { status: "not_available" };
|
|
102
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type { VoyantPermission } from "@voyant-travel/core";
|
|
2
|
+
export { createApp } from "./app.js";
|
|
3
|
+
export type { SessionAuthContext } from "./auth/index.js";
|
|
4
|
+
export { constantTimeEqual, extractBearerToken, generateNumericCode, randomBytesHex, requireUserId, sha256Base64Url, sha256Hex, unsignCookie, verifySession, } from "./auth/index.js";
|
|
5
|
+
export type { DocumentDownloadEnvelope, DocumentDownloadResolution, DocumentDownloadResolver, DocumentDownloadResolverResult, StoredDocumentReference, } from "./document-download.js";
|
|
6
|
+
export { resolveStoredDocumentDownload } from "./document-download.js";
|
|
7
|
+
export { createPathDbSelector, type PathDbSelectorOptions } from "./lib/db-selector.js";
|
|
8
|
+
export { clientIpKey, consoleLoggerProvider, cors, DEFAULT_IDEMPOTENCY_TTL_MS, db, enforceRateLimit, errorBoundary, handleApiError, type IdempotencyKeyOptions, idempotencyKey, LIVE_LIMITS, logger, purgeExpiredIdempotencyKeys, rateLimit, requestId, requireActor, requireAuth, requirePermission, } from "./middleware/index.js";
|
|
9
|
+
export type { HonoExtension, HonoModule } from "./module.js";
|
|
10
|
+
export type { ExpandedHonoBundles, ExpandedHonoPlugins, HonoBundle, HonoPlugin, } from "./plugin.js";
|
|
11
|
+
export { defineHonoBundle, defineHonoPlugin, expandHonoBundles, expandHonoPlugins, } from "./plugin.js";
|
|
12
|
+
export type { CreatePublicCapabilityOptions, PublicCapabilityCookieOptions, PublicCapabilityPayload, VerifyPublicCapabilityOptions, } from "./public-capability.js";
|
|
13
|
+
export { createPublicCapabilityToken, extractPublicCapabilityToken, serializePublicCapabilityCookie, verifyPublicCapabilityToken, } from "./public-capability.js";
|
|
14
|
+
export { type CreatePublicDocumentDeliveryInput, createDrizzlePublicDocumentDeliveryGrantStore, createPublicDocumentDeliveryGrant, createPublicDocumentDeliveryHonoModule, createPublicDocumentDeliveryRoutes, type PublicDocumentDeliveryAccessContext, type PublicDocumentDeliveryEnvelope, type PublicDocumentDeliveryGrant, type PublicDocumentDeliveryGrantStore, type PublicDocumentDeliveryResolution, type PublicDocumentDeliveryRouteOptions, type PublicDocumentDeliverySource, type RevokePublicDocumentDeliveryGrantInput, resolvePublicDocumentDeliveryGrant, revokePublicDocumentDeliveryGrant, } from "./public-document-delivery.js";
|
|
15
|
+
export type { DbFactory, DbFactorySelector, DbSource, DbSurfaceSelection, LogEntry, LoggerProvider, VoyantAppConfig, VoyantAuthIntegration, VoyantAuthPermissionArgs, VoyantAuthResolveArgs, VoyantBindings, VoyantDb, VoyantExecutionContext, VoyantQueryRuntime, VoyantRequestAuthContext, VoyantVariables, } from "./types.js";
|
|
16
|
+
export { ApiHttpError, ForbiddenApiError, normalizeValidationError, parseJsonBody, parseOptionalJsonBody, parseQuery, RequestValidationError, UnauthorizedApiError, } from "./validation.js";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,IAAI,EACJ,0BAA0B,EAC1B,EAAE,EACF,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,KAAK,qBAAqB,EAC1B,cAAc,EACd,WAAW,EACX,MAAM,EACN,2BAA2B,EAC3B,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC5D,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,6BAA6B,EAC7B,6BAA6B,EAC7B,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,KAAK,iCAAiC,EACtC,6CAA6C,EAC7C,iCAAiC,EACjC,sCAAsC,EACtC,kCAAkC,EAClC,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,gCAAgC,EACrC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,EAC3C,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,+BAA+B,CAAA;AACtC,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACxB,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createApp } from "./app.js";
|
|
2
|
+
export { constantTimeEqual, extractBearerToken, generateNumericCode, randomBytesHex, requireUserId, sha256Base64Url, sha256Hex, unsignCookie, verifySession, } from "./auth/index.js";
|
|
3
|
+
export { resolveStoredDocumentDownload } from "./document-download.js";
|
|
4
|
+
export { createPathDbSelector } from "./lib/db-selector.js";
|
|
5
|
+
export { clientIpKey, consoleLoggerProvider, cors, DEFAULT_IDEMPOTENCY_TTL_MS, db, enforceRateLimit, errorBoundary, handleApiError, idempotencyKey, LIVE_LIMITS, logger, purgeExpiredIdempotencyKeys, rateLimit, requestId, requireActor, requireAuth, requirePermission, } from "./middleware/index.js";
|
|
6
|
+
export { defineHonoBundle, defineHonoPlugin, expandHonoBundles, expandHonoPlugins, } from "./plugin.js";
|
|
7
|
+
export { createPublicCapabilityToken, extractPublicCapabilityToken, serializePublicCapabilityCookie, verifyPublicCapabilityToken, } from "./public-capability.js";
|
|
8
|
+
export { createDrizzlePublicDocumentDeliveryGrantStore, createPublicDocumentDeliveryGrant, createPublicDocumentDeliveryHonoModule, createPublicDocumentDeliveryRoutes, resolvePublicDocumentDeliveryGrant, revokePublicDocumentDeliveryGrant, } from "./public-document-delivery.js";
|
|
9
|
+
export { ApiHttpError, ForbiddenApiError, normalizeValidationError, parseJsonBody, parseOptionalJsonBody, parseQuery, RequestValidationError, UnauthorizedApiError, } from "./validation.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DbFactory, DbFactorySelector, VoyantBindings } from "../types.js";
|
|
2
|
+
export interface PathDbSelectorOptions<TBindings extends VoyantBindings> {
|
|
3
|
+
/** Serves every request not matched by a transactional prefix. */
|
|
4
|
+
defaultFactory: DbFactory<TBindings>;
|
|
5
|
+
/** Serves requests under the transactional prefixes. */
|
|
6
|
+
transactionalFactory: DbFactory<TBindings>;
|
|
7
|
+
/**
|
|
8
|
+
* Path prefixes (mount paths, no trailing slash) whose requests must
|
|
9
|
+
* receive the transactional client. Matching is exact-or-segment:
|
|
10
|
+
* `/v1/bookings` matches `/v1/bookings` and `/v1/bookings/x`, never
|
|
11
|
+
* `/v1/bookings-export`.
|
|
12
|
+
*/
|
|
13
|
+
transactionalPrefixes: readonly string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Path-based {@link DbFactorySelector}: route surfaces that run
|
|
17
|
+
* interactive transactions get the (expensive, WebSocket-backed)
|
|
18
|
+
* transactional factory; everything else gets the cheap default —
|
|
19
|
+
* typically neon-http, which costs no connection handshake. Returns
|
|
20
|
+
* stable factory references so per-request client sharing
|
|
21
|
+
* (`acquireRequestDb`) works across middlewares.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createPathDbSelector<TBindings extends VoyantBindings>(options: PathDbSelectorOptions<TBindings>): DbFactorySelector<TBindings>;
|
|
24
|
+
//# sourceMappingURL=db-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-selector.d.ts","sourceRoot":"","sources":["../../src/lib/db-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE/E,MAAM,WAAW,qBAAqB,CAAC,SAAS,SAAS,cAAc;IACrE,kEAAkE;IAClE,cAAc,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IACpC,wDAAwD;IACxD,oBAAoB,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IAC1C;;;;;OAKG;IACH,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAA;CACzC;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,SAAS,cAAc,EACnE,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,GACxC,iBAAiB,CAAC,SAAS,CAAC,CAkB9B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path-based {@link DbFactorySelector}: route surfaces that run
|
|
3
|
+
* interactive transactions get the (expensive, WebSocket-backed)
|
|
4
|
+
* transactional factory; everything else gets the cheap default —
|
|
5
|
+
* typically neon-http, which costs no connection handshake. Returns
|
|
6
|
+
* stable factory references so per-request client sharing
|
|
7
|
+
* (`acquireRequestDb`) works across middlewares.
|
|
8
|
+
*/
|
|
9
|
+
export function createPathDbSelector(options) {
|
|
10
|
+
const prefixes = [...new Set(options.transactionalPrefixes)];
|
|
11
|
+
const transactional = {
|
|
12
|
+
factory: options.transactionalFactory,
|
|
13
|
+
mustSupportTransactions: true,
|
|
14
|
+
};
|
|
15
|
+
const standard = {
|
|
16
|
+
factory: options.defaultFactory,
|
|
17
|
+
mustSupportTransactions: false,
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
select(path) {
|
|
21
|
+
for (const prefix of prefixes) {
|
|
22
|
+
if (path === prefix || path.startsWith(`${prefix}/`))
|
|
23
|
+
return transactional;
|
|
24
|
+
}
|
|
25
|
+
return standard;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural shape of the Cloudflare Workers `ExecutionContext`. Defined
|
|
3
|
+
* locally so `@voyant-travel/hono` doesn't need `@cloudflare/workers-types` —
|
|
4
|
+
* consumers on Node, Vercel, or any other runtime can use these helpers.
|
|
5
|
+
*/
|
|
6
|
+
export interface ExecutionContextLike {
|
|
7
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Hono throws on `executionCtx` access when the adapter provides none
|
|
11
|
+
* (Node tests, some serverless adapters) — normalize to undefined.
|
|
12
|
+
*/
|
|
13
|
+
export declare function tryGetExecutionCtx(c: {
|
|
14
|
+
executionCtx?: unknown;
|
|
15
|
+
}): ExecutionContextLike | undefined;
|
|
16
|
+
//# sourceMappingURL=execution-ctx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-ctx.d.ts","sourceRoot":"","sources":["../../src/lib/execution-ctx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;CAC3C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE;IACpC,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,GAAG,oBAAoB,GAAG,SAAS,CAUnC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono throws on `executionCtx` access when the adapter provides none
|
|
3
|
+
* (Node tests, some serverless adapters) — normalize to undefined.
|
|
4
|
+
*/
|
|
5
|
+
export function tryGetExecutionCtx(c) {
|
|
6
|
+
try {
|
|
7
|
+
const ctx = c.executionCtx;
|
|
8
|
+
if (ctx && typeof ctx.waitUntil === "function") {
|
|
9
|
+
return ctx;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// no ExecutionContext on this runtime
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `publicPaths` matching semantics.
|
|
3
|
+
*
|
|
4
|
+
* `requireAuth`, the legacy-surface guard, and the default rate-limit
|
|
5
|
+
* policies in `createApp` all need to answer "is this pathname covered
|
|
6
|
+
* by `config.publicPaths`?" with identical prefix-match semantics — a
|
|
7
|
+
* drifted copy of this check is an auth bypass (or a gap), so the
|
|
8
|
+
* matcher lives here and everyone imports it.
|
|
9
|
+
*/
|
|
10
|
+
/** Strip a single trailing slash so `/v1/x/` and `/v1/x` match alike. */
|
|
11
|
+
export declare function normalizePathname(pathname: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Whether `pathname` (pre-normalized via {@link normalizePathname}) is an
|
|
14
|
+
* exact match or a path-segment-prefixed match of any configured public
|
|
15
|
+
* path. `"/v1/public/checkout"` covers `/v1/public/checkout` and
|
|
16
|
+
* `/v1/public/checkout/anything`, but NOT `/v1/public/checkouts`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function matchesPublicPath(pathname: string, publicPaths: readonly string[]): boolean;
|
|
19
|
+
//# sourceMappingURL=public-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-paths.d.ts","sourceRoot":"","sources":["../../src/lib/public-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAO3F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `publicPaths` matching semantics.
|
|
3
|
+
*
|
|
4
|
+
* `requireAuth`, the legacy-surface guard, and the default rate-limit
|
|
5
|
+
* policies in `createApp` all need to answer "is this pathname covered
|
|
6
|
+
* by `config.publicPaths`?" with identical prefix-match semantics — a
|
|
7
|
+
* drifted copy of this check is an auth bypass (or a gap), so the
|
|
8
|
+
* matcher lives here and everyone imports it.
|
|
9
|
+
*/
|
|
10
|
+
/** Strip a single trailing slash so `/v1/x/` and `/v1/x` match alike. */
|
|
11
|
+
export function normalizePathname(pathname) {
|
|
12
|
+
return pathname.replace(/\/$/, "");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Whether `pathname` (pre-normalized via {@link normalizePathname}) is an
|
|
16
|
+
* exact match or a path-segment-prefixed match of any configured public
|
|
17
|
+
* path. `"/v1/public/checkout"` covers `/v1/public/checkout` and
|
|
18
|
+
* `/v1/public/checkout/anything`, but NOT `/v1/public/checkouts`.
|
|
19
|
+
*/
|
|
20
|
+
export function matchesPublicPath(pathname, publicPaths) {
|
|
21
|
+
for (const publicPath of publicPaths) {
|
|
22
|
+
if (pathname === publicPath || pathname.startsWith(`${publicPath}/`)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { EventBus, OutboxEventStore } from "@voyant-travel/core";
|
|
2
|
+
/**
|
|
3
|
+
* Wrap an {@link EventBus} so emits from within a request defer their
|
|
4
|
+
* (non-`inline`) subscribers past the HTTP response via the request's
|
|
5
|
+
* `executionCtx.waitUntil`. The response stops paying for subscriber
|
|
6
|
+
* work — third-party syncs (CMS, e-invoicing), notifications, workflow
|
|
7
|
+
* ingest — while `inline`-marked subscribers still complete before
|
|
8
|
+
* `emit()` resolves.
|
|
9
|
+
*
|
|
10
|
+
* With a `store` (transactional outbox), emits are also DURABLE: the
|
|
11
|
+
* envelope is persisted before any handler runs, and failed deliveries
|
|
12
|
+
* are retried by the drain. If the durable capture itself fails (DB
|
|
13
|
+
* unreachable), the emit falls back to direct (non-durable) delivery —
|
|
14
|
+
* losing durability for that one event is strictly better than losing
|
|
15
|
+
* the event, and an order of magnitude better than failing the request.
|
|
16
|
+
*
|
|
17
|
+
* Buses that predate the {@link EmitOptions} parameter simply ignore it
|
|
18
|
+
* and keep awaiting all handlers — a safe degradation.
|
|
19
|
+
*/
|
|
20
|
+
export declare function requestScopedEventBus(bus: EventBus, schedule: ((pending: Promise<unknown>) => void) | undefined, store?: OutboxEventStore): EventBus;
|
|
21
|
+
//# sourceMappingURL=request-event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-event-bus.d.ts","sourceRoot":"","sources":["../../src/lib/request-event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,QAAQ,EAAiB,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAEjG;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAC3D,KAAK,CAAC,EAAE,gBAAgB,GACvB,QAAQ,CA+BV"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrap an {@link EventBus} so emits from within a request defer their
|
|
3
|
+
* (non-`inline`) subscribers past the HTTP response via the request's
|
|
4
|
+
* `executionCtx.waitUntil`. The response stops paying for subscriber
|
|
5
|
+
* work — third-party syncs (CMS, e-invoicing), notifications, workflow
|
|
6
|
+
* ingest — while `inline`-marked subscribers still complete before
|
|
7
|
+
* `emit()` resolves.
|
|
8
|
+
*
|
|
9
|
+
* With a `store` (transactional outbox), emits are also DURABLE: the
|
|
10
|
+
* envelope is persisted before any handler runs, and failed deliveries
|
|
11
|
+
* are retried by the drain. If the durable capture itself fails (DB
|
|
12
|
+
* unreachable), the emit falls back to direct (non-durable) delivery —
|
|
13
|
+
* losing durability for that one event is strictly better than losing
|
|
14
|
+
* the event, and an order of magnitude better than failing the request.
|
|
15
|
+
*
|
|
16
|
+
* Buses that predate the {@link EmitOptions} parameter simply ignore it
|
|
17
|
+
* and keep awaiting all handlers — a safe degradation.
|
|
18
|
+
*/
|
|
19
|
+
export function requestScopedEventBus(bus, schedule, store) {
|
|
20
|
+
// Without a scheduler (Node/headless — no executionCtx), emits await
|
|
21
|
+
// all handlers inline, exactly like the raw bus; the wrapper then only
|
|
22
|
+
// exists to thread the outbox store through.
|
|
23
|
+
const base = schedule ? { schedule } : {};
|
|
24
|
+
return {
|
|
25
|
+
async emit(event, data, metadata, options) {
|
|
26
|
+
if (!store) {
|
|
27
|
+
return bus.emit(event, data, metadata, { ...base, ...options });
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return await bus.emit(event, data, metadata, { ...base, store, ...options });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
// Only the outbox insert can reject (handler errors are
|
|
34
|
+
// collected, bookkeeping failures are swallowed inside the bus).
|
|
35
|
+
console.error(`[events] outbox capture failed for "${event}" — falling back to direct delivery:`, err);
|
|
36
|
+
return bus.emit(event, data, metadata, { ...base, ...options });
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
subscribe(event, handler, options) {
|
|
40
|
+
return bus.subscribe(event, handler, options);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
import { type DbSource, type VoyantAuthIntegration, type VoyantBindings, type VoyantVariables } from "../types.js";
|
|
3
|
+
export declare function requireAuth<TBindings extends VoyantBindings>(dbSource: DbSource<TBindings>, opts?: {
|
|
4
|
+
publicPaths?: string[];
|
|
5
|
+
auth?: VoyantAuthIntegration<TBindings>;
|
|
6
|
+
}): MiddlewareHandler<{
|
|
7
|
+
Bindings: TBindings;
|
|
8
|
+
Variables: VoyantVariables;
|
|
9
|
+
}>;
|
|
10
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAM7C,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AA2GpB,wBAAgB,WAAW,CAAC,SAAS,SAAS,cAAc,EAC1D,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC7B,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,IAAI,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAA;CACxC,GACA,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CAyLD"}
|