@cloudnux/core-cloud-provider 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +79 -12
- package/dist/index.js +47 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -96,7 +96,7 @@ type Entrypoint = {
|
|
|
96
96
|
|
|
97
97
|
interface IService {
|
|
98
98
|
}
|
|
99
|
-
type ServiceKind = "storage" | "location" | "event-broker" | "functions" | "websocket" | "invoke" | "logger";
|
|
99
|
+
type ServiceKind = "storage" | "location" | "event-broker" | "functions" | "websocket" | "invoke" | "logger" | "email";
|
|
100
100
|
declare function registerService(kind: ServiceKind, factory: () => IService): void;
|
|
101
101
|
declare function registerServices(services: Record<ServiceKind, () => IService>): void;
|
|
102
102
|
declare function getService<T extends IService>(kind: ServiceKind): T;
|
|
@@ -391,10 +391,21 @@ declare enum ErrorCode {
|
|
|
391
391
|
EXTERNAL_API_ERROR = "EXTERNAL_API_ERROR",
|
|
392
392
|
UNKNOWN_ERROR = "UNKNOWN_ERROR"
|
|
393
393
|
}
|
|
394
|
+
type SameSite = "Strict" | "Lax" | "None";
|
|
395
|
+
type CookieOptions = {
|
|
396
|
+
path?: string;
|
|
397
|
+
domain?: string;
|
|
398
|
+
maxAge?: number;
|
|
399
|
+
expires?: Date;
|
|
400
|
+
httpOnly?: boolean;
|
|
401
|
+
secure?: boolean;
|
|
402
|
+
sameSite?: SameSite;
|
|
403
|
+
};
|
|
394
404
|
type HTTPRequest = {
|
|
395
405
|
method: HttpMethod;
|
|
396
406
|
body?: string;
|
|
397
407
|
headers: Record<string, string | string[] | undefined>;
|
|
408
|
+
cookies: Record<string, string>;
|
|
398
409
|
url: string;
|
|
399
410
|
params: Record<string, string | undefined>;
|
|
400
411
|
matchingKey?: string;
|
|
@@ -405,21 +416,13 @@ type HTTPRequest = {
|
|
|
405
416
|
};
|
|
406
417
|
type HTTPResponse = {
|
|
407
418
|
headers?: Record<string, string | string[] | undefined>;
|
|
419
|
+
cookies?: string[];
|
|
408
420
|
body?: string;
|
|
409
421
|
status: number;
|
|
410
422
|
};
|
|
411
|
-
type HTTPAuth = {
|
|
412
|
-
token: string;
|
|
413
|
-
appId: string;
|
|
414
|
-
memberId: string;
|
|
415
|
-
customerId: string;
|
|
416
|
-
claims: Record<string, string>;
|
|
417
|
-
identity: "facebook" | "google" | "apple" | "password";
|
|
418
|
-
};
|
|
419
423
|
type HttpFunctionContext = FunctionContext & {
|
|
420
424
|
type: "Http";
|
|
421
425
|
request: HTTPRequest;
|
|
422
|
-
auth?: HTTPAuth;
|
|
423
426
|
response: HTTPResponse;
|
|
424
427
|
model<T = Record<string, any>>(): T;
|
|
425
428
|
params<T = Record<string, string>>(): T;
|
|
@@ -433,6 +436,19 @@ type HttpFunctionContext = FunctionContext & {
|
|
|
433
436
|
unauthorized(message?: string): void;
|
|
434
437
|
forbidden(message?: string): void;
|
|
435
438
|
output(status: number, body?: string | object, headers?: Record<string, string | string[]>): void;
|
|
439
|
+
/**
|
|
440
|
+
* Queues a `Set-Cookie` header on the response.
|
|
441
|
+
* @param name - The cookie name.
|
|
442
|
+
* @param value - The cookie value.
|
|
443
|
+
* @param options - Cookie attributes (Path, Domain, Max-Age, Expires, HttpOnly, Secure, SameSite).
|
|
444
|
+
*/
|
|
445
|
+
setCookie(name: string, value: string, options?: CookieOptions): void;
|
|
446
|
+
/**
|
|
447
|
+
* Queues a `Set-Cookie` header that expires the named cookie immediately.
|
|
448
|
+
* @param name - The cookie name.
|
|
449
|
+
* @param options - Must match the Path/Domain the cookie was originally set with.
|
|
450
|
+
*/
|
|
451
|
+
deleteCookie(name: string, options?: Pick<CookieOptions, "path" | "domain">): void;
|
|
436
452
|
};
|
|
437
453
|
type ScheduleResponse = {
|
|
438
454
|
status: "success" | "error";
|
|
@@ -523,7 +539,7 @@ type WebSocketFunctionContext = FunctionContext & {
|
|
|
523
539
|
validationError(details: Record<string, any>): void;
|
|
524
540
|
};
|
|
525
541
|
interface FunctionsService extends IService {
|
|
526
|
-
createHttRequest(...args: any[]): [HTTPRequest
|
|
542
|
+
createHttRequest(...args: any[]): [HTTPRequest];
|
|
527
543
|
createScheduleRequest(...args: any[]): [ScheduleRequest];
|
|
528
544
|
createEventRequest(...args: any[]): [EventRequest];
|
|
529
545
|
createWebSocketRequest(...args: any[]): [WebSocketRequest];
|
|
@@ -535,6 +551,16 @@ interface FunctionsService extends IService {
|
|
|
535
551
|
buildInvokeResponse(invokeFunctionContext: InvokeFunctionContext, ...args: any[]): any;
|
|
536
552
|
}
|
|
537
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Serializes a single cookie into a `Set-Cookie` header value.
|
|
556
|
+
* Throws if `sameSite` is "None" without `secure` set, since browsers reject that combination.
|
|
557
|
+
*/
|
|
558
|
+
declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
|
|
559
|
+
/**
|
|
560
|
+
* Parses a raw `Cookie` request header (e.g. "a=1; b=2") into a name/value map.
|
|
561
|
+
*/
|
|
562
|
+
declare function parseCookieHeader(header?: string | null): Record<string, string>;
|
|
563
|
+
|
|
538
564
|
/**
|
|
539
565
|
* Thrown when a sendToClient/disconnect is attempted against a connectionId
|
|
540
566
|
* that is no longer connected (AWS API Gateway GoneException equivalent, HTTP 410).
|
|
@@ -557,6 +583,46 @@ interface WebSocketService {
|
|
|
557
583
|
disconnect(connectionId: string): Promise<void>;
|
|
558
584
|
}
|
|
559
585
|
|
|
586
|
+
type EmailAddress = string;
|
|
587
|
+
type EmailAttachment = {
|
|
588
|
+
filename: string;
|
|
589
|
+
content: Buffer | string;
|
|
590
|
+
contentType: string;
|
|
591
|
+
};
|
|
592
|
+
type EmailMessage = {
|
|
593
|
+
to: EmailAddress | EmailAddress[];
|
|
594
|
+
from: EmailAddress;
|
|
595
|
+
subject: string;
|
|
596
|
+
html?: string;
|
|
597
|
+
text?: string;
|
|
598
|
+
replyTo?: EmailAddress;
|
|
599
|
+
cc?: EmailAddress | EmailAddress[];
|
|
600
|
+
bcc?: EmailAddress | EmailAddress[];
|
|
601
|
+
attachments?: EmailAttachment[];
|
|
602
|
+
/**
|
|
603
|
+
* Named SES configuration set to send through (event destinations,
|
|
604
|
+
* reputation/dedicated-IP behavior, etc). No-op on providers that
|
|
605
|
+
* don't have the concept.
|
|
606
|
+
*/
|
|
607
|
+
configurationSet?: string;
|
|
608
|
+
/**
|
|
609
|
+
* Provider-specific passthrough (SES tags, ACS headers, etc).
|
|
610
|
+
* Adapters may use this; handlers should avoid depending on it
|
|
611
|
+
* to stay provider-agnostic.
|
|
612
|
+
*/
|
|
613
|
+
metadata?: Record<string, string>;
|
|
614
|
+
};
|
|
615
|
+
type EmailSendResult = {
|
|
616
|
+
status: "sent";
|
|
617
|
+
messageId: string;
|
|
618
|
+
} | {
|
|
619
|
+
status: "failed";
|
|
620
|
+
error: string;
|
|
621
|
+
};
|
|
622
|
+
interface EmailService extends IService {
|
|
623
|
+
send(message: EmailMessage): Promise<EmailSendResult>;
|
|
624
|
+
}
|
|
625
|
+
|
|
560
626
|
interface CloudProvider {
|
|
561
627
|
name: string;
|
|
562
628
|
createStorageService(): StorageService;
|
|
@@ -566,6 +632,7 @@ interface CloudProvider {
|
|
|
566
632
|
createWebSocketService(): WebSocketService;
|
|
567
633
|
createInvokeService(): InvokeService;
|
|
568
634
|
createLoggerService(): LoggerService;
|
|
635
|
+
createEmailService(): EmailService;
|
|
569
636
|
}
|
|
570
637
|
|
|
571
|
-
export { type BaseEntry, type CloudProvider, type Coordinates, type Entry, type Entrypoint, ErrorCode, type EventBatchItemResult, type EventBrokerService, type EventEntry, type EventFunctionContext, type EventMessage, type EventRequest, type EventResponse, type EventTrigger, type FunctionContext, type FunctionsService, type
|
|
638
|
+
export { type BaseEntry, type CloudProvider, type CookieOptions, type Coordinates, type EmailAddress, type EmailAttachment, type EmailMessage, type EmailSendResult, type EmailService, type Entry, type Entrypoint, ErrorCode, type EventBatchItemResult, type EventBrokerService, type EventEntry, type EventFunctionContext, type EventMessage, type EventRequest, type EventResponse, type EventTrigger, type FunctionContext, type FunctionsService, type HTTPRequest, type HTTPResponse, type HandlerType, type HttpEntry, type HttpFunctionContext, type HttpMethod, type HttpTrigger, type IService, type InvokeEntry, type InvokeFunctionContext, type InvokeRequest, type InvokeResponse, type InvokeService, type InvokeTrigger, type LocationAddress, type LocationProviderConfig, type LocationService, type LocationSuggestion, type LogEntry, type LoggerService, type MessageFilter, type PeekOptions, type PublishOptions, type ReadOptions, type ReverseGeocodeParams, type RoutePoint, type RouteResult, type SameSite, type ScheduleEntry, type ScheduleFunctionContext, type ScheduleRequest, type ScheduleResponse, type ScheduleTrigger, type ServiceKind, type StorageService, type StorageWriteOptions, type StorageWriteResult, type SuggestionParams, WebSocketConnectionGoneError, type WebSocketEntry, type WebSocketEvent, type WebSocketFunctionContext, type WebSocketRequest, type WebSocketResponse, type WebSocketService, type WebSocketTrigger, getService, parseCookieHeader, registerService, registerServices, serializeCookie };
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,48 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
|
16
16
|
return ErrorCode2;
|
|
17
17
|
})(ErrorCode || {});
|
|
18
18
|
|
|
19
|
+
// src/utils/cookies.ts
|
|
20
|
+
function serializeCookie(name, value, options = {}) {
|
|
21
|
+
const {
|
|
22
|
+
path = "/",
|
|
23
|
+
domain,
|
|
24
|
+
maxAge,
|
|
25
|
+
expires,
|
|
26
|
+
httpOnly = true,
|
|
27
|
+
secure = true,
|
|
28
|
+
sameSite = "Lax"
|
|
29
|
+
} = options;
|
|
30
|
+
if (sameSite === "None" && !secure) {
|
|
31
|
+
throw new Error(`Cookie "${name}" sets SameSite=None but not Secure; browsers require Secure with SameSite=None`);
|
|
32
|
+
}
|
|
33
|
+
const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
|
|
34
|
+
parts.push(`Path=${path}`);
|
|
35
|
+
if (domain) parts.push(`Domain=${domain}`);
|
|
36
|
+
if (maxAge !== void 0) parts.push(`Max-Age=${Math.trunc(maxAge)}`);
|
|
37
|
+
if (expires) parts.push(`Expires=${expires.toUTCString()}`);
|
|
38
|
+
if (httpOnly) parts.push("HttpOnly");
|
|
39
|
+
if (secure) parts.push("Secure");
|
|
40
|
+
parts.push(`SameSite=${sameSite}`);
|
|
41
|
+
return parts.join("; ");
|
|
42
|
+
}
|
|
43
|
+
function parseCookieHeader(header) {
|
|
44
|
+
const cookies = {};
|
|
45
|
+
if (!header) return cookies;
|
|
46
|
+
for (const pair of header.split(";")) {
|
|
47
|
+
const idx = pair.indexOf("=");
|
|
48
|
+
if (idx === -1) continue;
|
|
49
|
+
const name = pair.slice(0, idx).trim();
|
|
50
|
+
const value = pair.slice(idx + 1).trim();
|
|
51
|
+
if (!name) continue;
|
|
52
|
+
try {
|
|
53
|
+
cookies[name] = decodeURIComponent(value);
|
|
54
|
+
} catch {
|
|
55
|
+
cookies[name] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return cookies;
|
|
59
|
+
}
|
|
60
|
+
|
|
19
61
|
// src/services/websocket.ts
|
|
20
62
|
var WebSocketConnectionGoneError = class extends Error {
|
|
21
63
|
connectionId;
|
|
@@ -34,7 +76,8 @@ var _cloudContainer = {
|
|
|
34
76
|
functions: void 0,
|
|
35
77
|
websocket: void 0,
|
|
36
78
|
invoke: void 0,
|
|
37
|
-
logger: void 0
|
|
79
|
+
logger: void 0,
|
|
80
|
+
email: void 0
|
|
38
81
|
};
|
|
39
82
|
function registerService(kind, factory) {
|
|
40
83
|
_cloudContainer[kind] = factory;
|
|
@@ -57,7 +100,9 @@ export {
|
|
|
57
100
|
ErrorCode,
|
|
58
101
|
WebSocketConnectionGoneError,
|
|
59
102
|
getService,
|
|
103
|
+
parseCookieHeader,
|
|
60
104
|
registerService,
|
|
61
|
-
registerServices
|
|
105
|
+
registerServices,
|
|
106
|
+
serializeCookie
|
|
62
107
|
};
|
|
63
108
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/functions.ts","../src/services/websocket.ts","../src/cloud-container.ts"],"sourcesContent":["import { IService } from \"../cloud-container\";\nimport { HandlerType, HttpMethod, WebSocketEvent } from \"../entrypoint\";\nimport { LoggerService } from \"./logger\";\n\n/**\n * Represents the context object for a function handler.\n */\nexport type FunctionContext = {\n /**\n * The underlying context handler type.\n */\n type: HandlerType;\n\n /**\n * Logger bound to this invocation's module name and request id.\n */\n logger: LoggerService;\n\n /**\n * Creates a success response. This should be called when the handler is done successfully.\n * @param data - The response body.\n */\n success<T>(data: T): void;\n\n /**\n * Creates a server error response. This should be called when the handler encounters an unexpected error.\n * @param err - The error object.\n */\n serverError(err: Error): void;\n /**\n * Creates an error response. This should be called when the handler is done with an error.\n * @param message - The response body.\n * \n */\n error(message: string, code?: ErrorCode, details?: Record<string, any>, stack?: string): void;\n /**\n * Creates a not found response. This should be called when the requested resource is not found.\n * @param resource - The name of the resource that was not found.\n * @param id - The id of the resource that was not found (optional).\n */\n notFound(resource: string, id?: string | number): void;\n};\n\n/**\n * Error codes for API error responses\n */\nexport enum ErrorCode {\n // Validation errors\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n INVALID_INPUT = 'INVALID_INPUT',\n\n // Authentication errors\n UNAUTHORIZED = 'UNAUTHORIZED',\n ACCESS_DENIED = 'ACCESS_DENIED',\n\n // Resource errors\n RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',\n RESOURCE_ALREADY_EXISTS = 'RESOURCE_ALREADY_EXISTS',\n RESOURCE_CONFLICT = 'RESOURCE_CONFLICT',\n\n // System errors\n INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR',\n SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',\n DATABASE_ERROR = 'DATABASE_ERROR',\n\n // Business logic errors\n BUSINESS_RULE_VIOLATION = 'BUSINESS_RULE_VIOLATION',\n\n // External API errors\n EXTERNAL_API_ERROR = 'EXTERNAL_API_ERROR',\n\n // Other errors\n UNKNOWN_ERROR = 'UNKNOWN_ERROR'\n}\n\n//#region [ Http ]\n\nexport type HTTPRequest = {\n method: HttpMethod;\n body?: string;\n headers: Record<string, string | string[] | undefined>;\n url: string;\n params: Record<string, string | undefined>\n matchingKey?: string;\n rawQueryString?: string,\n requestId?: string,\n host?: string,\n moduleName?: string,\n};\n\nexport type HTTPResponse = {\n headers?: Record<string, string | string[] | undefined>;\n body?: string;\n status: number;\n};\n\nexport type HTTPAuth = {\n token: string;\n appId: string;\n memberId: string;\n customerId: string;\n claims: Record<string, string>;\n identity: \"facebook\" | \"google\" | \"apple\" | \"password\";\n};\n\nexport type HttpFunctionContext = FunctionContext & {\n type: \"Http\";\n request: HTTPRequest;\n auth?: HTTPAuth;\n response: HTTPResponse;\n model<T = Record<string, any>>(): T;\n params<T = Record<string, string>>(): T;\n\n list<T>(items: T[], page: number, pageSize: number, totalItems: number): void;\n cursorList<T>(items: T[], nextCursor: string | null, pageSize: number, prevCursor?: string | null): void;\n created<T>(data: T): void;\n deleted(id?: string | number): void;\n validationError(details: Record<string, any>): void;\n serverError(err: Error): void;\n businessError(message: string, details?: Record<string, any>): void;\n\n unauthorized(message?: string): void;\n forbidden(message?: string): void;\n output(status: number, body?: string | object, headers?: Record<string, string | string[]>): void;\n}\n\n//#endregion\n\n//#region [Schedule]\n\nexport type ScheduleResponse = {\n status: \"success\" | \"error\",\n body?: string | Record<string, any>;\n}\n\nexport type ScheduleRequest = {\n name: string,\n requestId?: string,\n moduleName?: string,\n};\n\nexport type ScheduleFunctionContext = FunctionContext & {\n response: ScheduleResponse;\n request: ScheduleRequest;\n type: \"Schedule\";\n}\n//#endregion\n\n//#region [Event]\nexport type EventRequest = {\n body: string | Record<string, any>,\n attributes: Record<string, string>,\n requestId?: string,\n timestamp: Date,\n attempts?: number;\n moduleName?: string,\n}\n\nexport type EventResponse = {\n status: \"success\" | \"error\",\n code?: ErrorCode,\n body?: Record<string, any>\n stack?: string,\n retryDelay?: number,\n};\n\nexport type EventFunctionContext = FunctionContext & {\n type: \"Event\";\n timestamp: Date;\n attempts?: number;\n request: EventRequest;\n response: EventResponse;\n message<T = Record<string, any>>(): T;\n attributes<T = Record<string, any>>(): T;\n retryWithDelay(seconds: number): void;\n}\n\nexport type EventBatchItemResult = { failureId: string } | undefined;\n//#endregion\n\n//#region [Invoke]\nexport type InvokeRequest = {\n payload: any,\n calledModule: string,\n invokeTriggerName: string,\n requestId?: string,\n}\n\nexport type InvokeResponse = {\n status: \"success\" | \"error\",\n body?: any,\n code?: ErrorCode,\n}\n\nexport type InvokeFunctionContext = FunctionContext & {\n type: \"Invoke\";\n request: InvokeRequest;\n response: InvokeResponse;\n payload<T = Record<string, any>>(): T;\n}\n//#endregion\n\n//#region [WebSocket]\nexport type WebSocketRequest = {\n connectionId: string,\n event: WebSocketEvent,\n route?: string,\n url?: string,\n params: Record<string, string | undefined> | null,\n body?: string | Record<string, any> | null,\n headers?: Record<string, string | string[] | undefined>,\n queryString: Record<string, string | undefined> | null,\n requestId?: string,\n moduleName?: string,\n}\n\nexport type WebSocketResponse = {\n status: \"success\" | \"error\",\n statusCode?: number,\n body?: any,\n}\n\nexport type WebSocketFunctionContext = FunctionContext & {\n type: \"WebSocket\";\n connectionId: string;\n event: WebSocketEvent;\n request: WebSocketRequest;\n response: WebSocketResponse;\n message<T = Record<string, any>>(): T;\n params<T = Record<string, string>>(): T;\n unauthorized(body?: any): void;\n forbidden(body?: any): void;\n validationError(details: Record<string, any>): void;\n}\n//#endregion\n\nexport interface FunctionsService extends IService {\n createHttRequest(...args: any[]): [HTTPRequest, HTTPAuth?];\n createScheduleRequest(...args: any[]): [ScheduleRequest];\n createEventRequest(...args: any[]): [EventRequest];\n createWebSocketRequest(...args: any[]): [WebSocketRequest];\n createInvokeRequest(...args: any[]): [InvokeRequest];\n\n buildHttpResponse(httpFunctionContext: HttpFunctionContext, ...args: any[]): any\n buildScheduleResponse(scheduleFunctionContext: ScheduleFunctionContext, ...args: any[]): any;\n buildEventResponse(eventFunctionContext: EventFunctionContext, ...args: any[]): Promise<EventBatchItemResult>;\n buildWebSocketResponse(webSocketFunctionContext: WebSocketFunctionContext, ...args: any[]): any;\n buildInvokeResponse(invokeFunctionContext: InvokeFunctionContext, ...args: any[]): any;\n}","/**\n * Thrown when a sendToClient/disconnect is attempted against a connectionId\n * that is no longer connected (AWS API Gateway GoneException equivalent, HTTP 410).\n */\nexport class WebSocketConnectionGoneError extends Error {\n public readonly connectionId: string;\n\n constructor(connectionId: string) {\n super(`WebSocket connection ${connectionId} is gone`);\n this.name = \"WebSocketConnectionGoneError\";\n this.connectionId = connectionId;\n }\n}\n\nexport interface WebSocketService {\n /**\n * Send a message to a specific connected client\n * @param connectionId The connection ID of the target client\n * @param data The data to send\n */\n sendToClient(connectionId: string, data: any): Promise<void>;\n\n /**\n * Disconnect a specific connected client\n * @param connectionId The connection ID of the client to disconnect\n */\n disconnect(connectionId: string): Promise<void>;\n}\n","export interface IService { };\nexport type ServiceKind = \"storage\" | \"location\" | \"event-broker\" | \"functions\" | \"websocket\" | \"invoke\" | \"logger\";\n\n\nconst _cloudContainer: Record<ServiceKind, (() => IService) | undefined> = {\n storage: undefined,\n location: undefined,\n \"event-broker\": undefined,\n functions: undefined,\n websocket: undefined,\n invoke: undefined,\n logger: undefined\n};\n\nexport function registerService(kind: ServiceKind, factory: () => IService) {\n _cloudContainer[kind] = factory;\n}\n\nexport function registerServices(services: Record<ServiceKind, () => IService>) {\n for (const kind in services) {\n if (services.hasOwnProperty(kind)) {\n _cloudContainer[kind as ServiceKind] = services[kind as ServiceKind];\n }\n }\n}\n\nexport function getService<T extends IService>(kind: ServiceKind): T {\n const service = _cloudContainer[kind];\n if (!service) {\n throw new Error(`Service of kind ${kind} is not registered.`);\n }\n return service() as T;\n}\n"],"mappings":";AA8CO,IAAK,YAAL,kBAAKA,eAAL;AAEH,EAAAA,WAAA,sBAAmB;AACnB,EAAAA,WAAA,mBAAgB;AAGhB,EAAAA,WAAA,kBAAe;AACf,EAAAA,WAAA,mBAAgB;AAGhB,EAAAA,WAAA,wBAAqB;AACrB,EAAAA,WAAA,6BAA0B;AAC1B,EAAAA,WAAA,uBAAoB;AAGpB,EAAAA,WAAA,2BAAwB;AACxB,EAAAA,WAAA,yBAAsB;AACtB,EAAAA,WAAA,oBAAiB;AAGjB,EAAAA,WAAA,6BAA0B;AAG1B,EAAAA,WAAA,wBAAqB;AAGrB,EAAAA,WAAA,mBAAgB;AA1BR,SAAAA;AAAA,GAAA;;;AC1CL,IAAM,+BAAN,cAA2C,MAAM;AAAA,EACpC;AAAA,EAEhB,YAAY,cAAsB;AAC9B,UAAM,wBAAwB,YAAY,UAAU;AACpD,SAAK,OAAO;AACZ,SAAK,eAAe;AAAA,EACxB;AACJ;;;ACRA,IAAM,kBAAqE;AAAA,EACvE,SAAS;AAAA,EACT,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AACZ;AAEO,SAAS,gBAAgB,MAAmB,SAAyB;AACxE,kBAAgB,IAAI,IAAI;AAC5B;AAEO,SAAS,iBAAiB,UAA+C;AAC5E,aAAW,QAAQ,UAAU;AACzB,QAAI,SAAS,eAAe,IAAI,GAAG;AAC/B,sBAAgB,IAAmB,IAAI,SAAS,IAAmB;AAAA,IACvE;AAAA,EACJ;AACJ;AAEO,SAAS,WAA+B,MAAsB;AACjE,QAAM,UAAU,gBAAgB,IAAI;AACpC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,mBAAmB,IAAI,qBAAqB;AAAA,EAChE;AACA,SAAO,QAAQ;AACnB;","names":["ErrorCode"]}
|
|
1
|
+
{"version":3,"sources":["../src/services/functions.ts","../src/utils/cookies.ts","../src/services/websocket.ts","../src/cloud-container.ts"],"sourcesContent":["import { IService } from \"../cloud-container\";\nimport { HandlerType, HttpMethod, WebSocketEvent } from \"../entrypoint\";\nimport { LoggerService } from \"./logger\";\n\n/**\n * Represents the context object for a function handler.\n */\nexport type FunctionContext = {\n /**\n * The underlying context handler type.\n */\n type: HandlerType;\n\n /**\n * Logger bound to this invocation's module name and request id.\n */\n logger: LoggerService;\n\n /**\n * Creates a success response. This should be called when the handler is done successfully.\n * @param data - The response body.\n */\n success<T>(data: T): void;\n\n /**\n * Creates a server error response. This should be called when the handler encounters an unexpected error.\n * @param err - The error object.\n */\n serverError(err: Error): void;\n /**\n * Creates an error response. This should be called when the handler is done with an error.\n * @param message - The response body.\n * \n */\n error(message: string, code?: ErrorCode, details?: Record<string, any>, stack?: string): void;\n /**\n * Creates a not found response. This should be called when the requested resource is not found.\n * @param resource - The name of the resource that was not found.\n * @param id - The id of the resource that was not found (optional).\n */\n notFound(resource: string, id?: string | number): void;\n};\n\n/**\n * Error codes for API error responses\n */\nexport enum ErrorCode {\n // Validation errors\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n INVALID_INPUT = 'INVALID_INPUT',\n\n // Authentication errors\n UNAUTHORIZED = 'UNAUTHORIZED',\n ACCESS_DENIED = 'ACCESS_DENIED',\n\n // Resource errors\n RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',\n RESOURCE_ALREADY_EXISTS = 'RESOURCE_ALREADY_EXISTS',\n RESOURCE_CONFLICT = 'RESOURCE_CONFLICT',\n\n // System errors\n INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR',\n SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',\n DATABASE_ERROR = 'DATABASE_ERROR',\n\n // Business logic errors\n BUSINESS_RULE_VIOLATION = 'BUSINESS_RULE_VIOLATION',\n\n // External API errors\n EXTERNAL_API_ERROR = 'EXTERNAL_API_ERROR',\n\n // Other errors\n UNKNOWN_ERROR = 'UNKNOWN_ERROR'\n}\n\n//#region [ Http ]\n\nexport type SameSite = \"Strict\" | \"Lax\" | \"None\";\n\nexport type CookieOptions = {\n path?: string;\n domain?: string;\n maxAge?: number;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: SameSite;\n};\n\nexport type HTTPRequest = {\n method: HttpMethod;\n body?: string;\n headers: Record<string, string | string[] | undefined>;\n cookies: Record<string, string>;\n url: string;\n params: Record<string, string | undefined>\n matchingKey?: string;\n rawQueryString?: string,\n requestId?: string,\n host?: string,\n moduleName?: string,\n};\n\nexport type HTTPResponse = {\n headers?: Record<string, string | string[] | undefined>;\n cookies?: string[];\n body?: string;\n status: number;\n};\n\nexport type HttpFunctionContext = FunctionContext & {\n type: \"Http\";\n request: HTTPRequest;\n response: HTTPResponse;\n model<T = Record<string, any>>(): T;\n params<T = Record<string, string>>(): T;\n\n list<T>(items: T[], page: number, pageSize: number, totalItems: number): void;\n cursorList<T>(items: T[], nextCursor: string | null, pageSize: number, prevCursor?: string | null): void;\n created<T>(data: T): void;\n deleted(id?: string | number): void;\n validationError(details: Record<string, any>): void;\n serverError(err: Error): void;\n businessError(message: string, details?: Record<string, any>): void;\n\n unauthorized(message?: string): void;\n forbidden(message?: string): void;\n output(status: number, body?: string | object, headers?: Record<string, string | string[]>): void;\n\n /**\n * Queues a `Set-Cookie` header on the response.\n * @param name - The cookie name.\n * @param value - The cookie value.\n * @param options - Cookie attributes (Path, Domain, Max-Age, Expires, HttpOnly, Secure, SameSite).\n */\n setCookie(name: string, value: string, options?: CookieOptions): void;\n /**\n * Queues a `Set-Cookie` header that expires the named cookie immediately.\n * @param name - The cookie name.\n * @param options - Must match the Path/Domain the cookie was originally set with.\n */\n deleteCookie(name: string, options?: Pick<CookieOptions, \"path\" | \"domain\">): void;\n}\n\n//#endregion\n\n//#region [Schedule]\n\nexport type ScheduleResponse = {\n status: \"success\" | \"error\",\n body?: string | Record<string, any>;\n}\n\nexport type ScheduleRequest = {\n name: string,\n requestId?: string,\n moduleName?: string,\n};\n\nexport type ScheduleFunctionContext = FunctionContext & {\n response: ScheduleResponse;\n request: ScheduleRequest;\n type: \"Schedule\";\n}\n//#endregion\n\n//#region [Event]\nexport type EventRequest = {\n body: string | Record<string, any>,\n attributes: Record<string, string>,\n requestId?: string,\n timestamp: Date,\n attempts?: number;\n moduleName?: string,\n}\n\nexport type EventResponse = {\n status: \"success\" | \"error\",\n code?: ErrorCode,\n body?: Record<string, any>\n stack?: string,\n retryDelay?: number,\n};\n\nexport type EventFunctionContext = FunctionContext & {\n type: \"Event\";\n timestamp: Date;\n attempts?: number;\n request: EventRequest;\n response: EventResponse;\n message<T = Record<string, any>>(): T;\n attributes<T = Record<string, any>>(): T;\n retryWithDelay(seconds: number): void;\n}\n\nexport type EventBatchItemResult = { failureId: string } | undefined;\n//#endregion\n\n//#region [Invoke]\nexport type InvokeRequest = {\n payload: any,\n calledModule: string,\n invokeTriggerName: string,\n requestId?: string,\n}\n\nexport type InvokeResponse = {\n status: \"success\" | \"error\",\n body?: any,\n code?: ErrorCode,\n}\n\nexport type InvokeFunctionContext = FunctionContext & {\n type: \"Invoke\";\n request: InvokeRequest;\n response: InvokeResponse;\n payload<T = Record<string, any>>(): T;\n}\n//#endregion\n\n//#region [WebSocket]\nexport type WebSocketRequest = {\n connectionId: string,\n event: WebSocketEvent,\n route?: string,\n url?: string,\n params: Record<string, string | undefined> | null,\n body?: string | Record<string, any> | null,\n headers?: Record<string, string | string[] | undefined>,\n queryString: Record<string, string | undefined> | null,\n requestId?: string,\n moduleName?: string,\n}\n\nexport type WebSocketResponse = {\n status: \"success\" | \"error\",\n statusCode?: number,\n body?: any,\n}\n\nexport type WebSocketFunctionContext = FunctionContext & {\n type: \"WebSocket\";\n connectionId: string;\n event: WebSocketEvent;\n request: WebSocketRequest;\n response: WebSocketResponse;\n message<T = Record<string, any>>(): T;\n params<T = Record<string, string>>(): T;\n unauthorized(body?: any): void;\n forbidden(body?: any): void;\n validationError(details: Record<string, any>): void;\n}\n//#endregion\n\nexport interface FunctionsService extends IService {\n createHttRequest(...args: any[]): [HTTPRequest];\n createScheduleRequest(...args: any[]): [ScheduleRequest];\n createEventRequest(...args: any[]): [EventRequest];\n createWebSocketRequest(...args: any[]): [WebSocketRequest];\n createInvokeRequest(...args: any[]): [InvokeRequest];\n\n buildHttpResponse(httpFunctionContext: HttpFunctionContext, ...args: any[]): any\n buildScheduleResponse(scheduleFunctionContext: ScheduleFunctionContext, ...args: any[]): any;\n buildEventResponse(eventFunctionContext: EventFunctionContext, ...args: any[]): Promise<EventBatchItemResult>;\n buildWebSocketResponse(webSocketFunctionContext: WebSocketFunctionContext, ...args: any[]): any;\n buildInvokeResponse(invokeFunctionContext: InvokeFunctionContext, ...args: any[]): any;\n}","import { CookieOptions } from \"../services/functions\";\n\n/**\n * Serializes a single cookie into a `Set-Cookie` header value.\n * Throws if `sameSite` is \"None\" without `secure` set, since browsers reject that combination.\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n const {\n path = \"/\",\n domain,\n maxAge,\n expires,\n httpOnly = true,\n secure = true,\n sameSite = \"Lax\",\n } = options;\n\n if (sameSite === \"None\" && !secure) {\n throw new Error(`Cookie \"${name}\" sets SameSite=None but not Secure; browsers require Secure with SameSite=None`);\n }\n\n const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];\n parts.push(`Path=${path}`);\n if (domain) parts.push(`Domain=${domain}`);\n if (maxAge !== undefined) parts.push(`Max-Age=${Math.trunc(maxAge)}`);\n if (expires) parts.push(`Expires=${expires.toUTCString()}`);\n if (httpOnly) parts.push(\"HttpOnly\");\n if (secure) parts.push(\"Secure\");\n parts.push(`SameSite=${sameSite}`);\n\n return parts.join(\"; \");\n}\n\n/**\n * Parses a raw `Cookie` request header (e.g. \"a=1; b=2\") into a name/value map.\n */\nexport function parseCookieHeader(header?: string | null): Record<string, string> {\n const cookies: Record<string, string> = {};\n if (!header) return cookies;\n\n for (const pair of header.split(\";\")) {\n const idx = pair.indexOf(\"=\");\n if (idx === -1) continue;\n\n const name = pair.slice(0, idx).trim();\n const value = pair.slice(idx + 1).trim();\n if (!name) continue;\n\n try {\n cookies[name] = decodeURIComponent(value);\n } catch {\n cookies[name] = value;\n }\n }\n\n return cookies;\n}\n","/**\n * Thrown when a sendToClient/disconnect is attempted against a connectionId\n * that is no longer connected (AWS API Gateway GoneException equivalent, HTTP 410).\n */\nexport class WebSocketConnectionGoneError extends Error {\n public readonly connectionId: string;\n\n constructor(connectionId: string) {\n super(`WebSocket connection ${connectionId} is gone`);\n this.name = \"WebSocketConnectionGoneError\";\n this.connectionId = connectionId;\n }\n}\n\nexport interface WebSocketService {\n /**\n * Send a message to a specific connected client\n * @param connectionId The connection ID of the target client\n * @param data The data to send\n */\n sendToClient(connectionId: string, data: any): Promise<void>;\n\n /**\n * Disconnect a specific connected client\n * @param connectionId The connection ID of the client to disconnect\n */\n disconnect(connectionId: string): Promise<void>;\n}\n","export interface IService { };\nexport type ServiceKind = \"storage\" | \"location\" | \"event-broker\" | \"functions\" | \"websocket\" | \"invoke\" | \"logger\" | \"email\";\n\n\nconst _cloudContainer: Record<ServiceKind, (() => IService) | undefined> = {\n storage: undefined,\n location: undefined,\n \"event-broker\": undefined,\n functions: undefined,\n websocket: undefined,\n invoke: undefined,\n logger: undefined,\n email: undefined\n};\n\nexport function registerService(kind: ServiceKind, factory: () => IService) {\n _cloudContainer[kind] = factory;\n}\n\nexport function registerServices(services: Record<ServiceKind, () => IService>) {\n for (const kind in services) {\n if (services.hasOwnProperty(kind)) {\n _cloudContainer[kind as ServiceKind] = services[kind as ServiceKind];\n }\n }\n}\n\nexport function getService<T extends IService>(kind: ServiceKind): T {\n const service = _cloudContainer[kind];\n if (!service) {\n throw new Error(`Service of kind ${kind} is not registered.`);\n }\n return service() as T;\n}\n"],"mappings":";AA8CO,IAAK,YAAL,kBAAKA,eAAL;AAEH,EAAAA,WAAA,sBAAmB;AACnB,EAAAA,WAAA,mBAAgB;AAGhB,EAAAA,WAAA,kBAAe;AACf,EAAAA,WAAA,mBAAgB;AAGhB,EAAAA,WAAA,wBAAqB;AACrB,EAAAA,WAAA,6BAA0B;AAC1B,EAAAA,WAAA,uBAAoB;AAGpB,EAAAA,WAAA,2BAAwB;AACxB,EAAAA,WAAA,yBAAsB;AACtB,EAAAA,WAAA,oBAAiB;AAGjB,EAAAA,WAAA,6BAA0B;AAG1B,EAAAA,WAAA,wBAAqB;AAGrB,EAAAA,WAAA,mBAAgB;AA1BR,SAAAA;AAAA,GAAA;;;ACxCL,SAAS,gBAAgB,MAAc,OAAe,UAAyB,CAAC,GAAW;AAC9F,QAAM;AAAA,IACF,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,SAAS;AAAA,IACT,WAAW;AAAA,EACf,IAAI;AAEJ,MAAI,aAAa,UAAU,CAAC,QAAQ;AAChC,UAAM,IAAI,MAAM,WAAW,IAAI,iFAAiF;AAAA,EACpH;AAEA,QAAM,QAAQ,CAAC,GAAG,mBAAmB,IAAI,CAAC,IAAI,mBAAmB,KAAK,CAAC,EAAE;AACzE,QAAM,KAAK,QAAQ,IAAI,EAAE;AACzB,MAAI,OAAQ,OAAM,KAAK,UAAU,MAAM,EAAE;AACzC,MAAI,WAAW,OAAW,OAAM,KAAK,WAAW,KAAK,MAAM,MAAM,CAAC,EAAE;AACpE,MAAI,QAAS,OAAM,KAAK,WAAW,QAAQ,YAAY,CAAC,EAAE;AAC1D,MAAI,SAAU,OAAM,KAAK,UAAU;AACnC,MAAI,OAAQ,OAAM,KAAK,QAAQ;AAC/B,QAAM,KAAK,YAAY,QAAQ,EAAE;AAEjC,SAAO,MAAM,KAAK,IAAI;AAC1B;AAKO,SAAS,kBAAkB,QAAgD;AAC9E,QAAM,UAAkC,CAAC;AACzC,MAAI,CAAC,OAAQ,QAAO;AAEpB,aAAW,QAAQ,OAAO,MAAM,GAAG,GAAG;AAClC,UAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,QAAI,QAAQ,GAAI;AAEhB,UAAM,OAAO,KAAK,MAAM,GAAG,GAAG,EAAE,KAAK;AACrC,UAAM,QAAQ,KAAK,MAAM,MAAM,CAAC,EAAE,KAAK;AACvC,QAAI,CAAC,KAAM;AAEX,QAAI;AACA,cAAQ,IAAI,IAAI,mBAAmB,KAAK;AAAA,IAC5C,QAAQ;AACJ,cAAQ,IAAI,IAAI;AAAA,IACpB;AAAA,EACJ;AAEA,SAAO;AACX;;;ACpDO,IAAM,+BAAN,cAA2C,MAAM;AAAA,EACpC;AAAA,EAEhB,YAAY,cAAsB;AAC9B,UAAM,wBAAwB,YAAY,UAAU;AACpD,SAAK,OAAO;AACZ,SAAK,eAAe;AAAA,EACxB;AACJ;;;ACRA,IAAM,kBAAqE;AAAA,EACvE,SAAS;AAAA,EACT,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AACX;AAEO,SAAS,gBAAgB,MAAmB,SAAyB;AACxE,kBAAgB,IAAI,IAAI;AAC5B;AAEO,SAAS,iBAAiB,UAA+C;AAC5E,aAAW,QAAQ,UAAU;AACzB,QAAI,SAAS,eAAe,IAAI,GAAG;AAC/B,sBAAgB,IAAmB,IAAI,SAAS,IAAmB;AAAA,IACvE;AAAA,EACJ;AACJ;AAEO,SAAS,WAA+B,MAAsB;AACjE,QAAM,UAAU,gBAAgB,IAAI;AACpC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,mBAAmB,IAAI,qBAAqB;AAAA,EAChE;AACA,SAAO,QAAQ;AACnB;","names":["ErrorCode"]}
|