@playdrop/playdrop-cli 0.7.0 → 0.7.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.
Files changed (66) hide show
  1. package/config/client-meta.json +8 -8
  2. package/dist/commands/generation.d.ts +2 -0
  3. package/dist/commands/generation.js +61 -4
  4. package/dist/commands/versionsBrowse.js +63 -4
  5. package/dist/environment.d.ts +1 -1
  6. package/dist/environment.js +24 -1
  7. package/dist/index.js +16 -2
  8. package/node_modules/@playdrop/ai-client/dist/index.d.ts +37 -5
  9. package/node_modules/@playdrop/ai-client/dist/index.d.ts.map +1 -1
  10. package/node_modules/@playdrop/ai-client/dist/index.js +10 -1
  11. package/node_modules/@playdrop/ai-client/package.json +1 -1
  12. package/node_modules/@playdrop/api-client/dist/client.d.ts +10 -2
  13. package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
  14. package/node_modules/@playdrop/api-client/dist/client.js +74 -0
  15. package/node_modules/@playdrop/api-client/dist/core/request.d.ts.map +1 -1
  16. package/node_modules/@playdrop/api-client/dist/core/request.js +64 -12
  17. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +1 -2
  18. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
  19. package/node_modules/@playdrop/api-client/dist/domains/admin.js +0 -11
  20. package/node_modules/@playdrop/api-client/dist/domains/comments.d.ts +4 -1
  21. package/node_modules/@playdrop/api-client/dist/domains/comments.d.ts.map +1 -1
  22. package/node_modules/@playdrop/api-client/dist/domains/comments.js +34 -0
  23. package/node_modules/@playdrop/api-client/dist/index.d.ts +11 -4
  24. package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
  25. package/node_modules/@playdrop/api-client/dist/index.js +27 -3
  26. package/node_modules/@playdrop/api-client/package.json +1 -1
  27. package/node_modules/@playdrop/boxel-core/package.json +3 -4
  28. package/node_modules/@playdrop/boxel-three/package.json +1 -1
  29. package/node_modules/@playdrop/config/client-meta.json +8 -8
  30. package/node_modules/@playdrop/config/dist/src/deployment.d.ts +27 -0
  31. package/node_modules/@playdrop/config/dist/src/deployment.d.ts.map +1 -0
  32. package/node_modules/@playdrop/config/dist/src/deployment.js +199 -0
  33. package/node_modules/@playdrop/config/dist/src/index.d.ts +2 -0
  34. package/node_modules/@playdrop/config/dist/src/index.d.ts.map +1 -1
  35. package/node_modules/@playdrop/config/dist/src/index.js +2 -0
  36. package/node_modules/@playdrop/config/dist/src/public-deployment.d.ts +26 -0
  37. package/node_modules/@playdrop/config/dist/src/public-deployment.d.ts.map +1 -0
  38. package/node_modules/@playdrop/config/dist/src/public-deployment.js +148 -0
  39. package/node_modules/@playdrop/config/dist/src/server/fastify.d.ts +60 -1
  40. package/node_modules/@playdrop/config/dist/src/server/fastify.d.ts.map +1 -1
  41. package/node_modules/@playdrop/config/dist/src/server/fastify.js +119 -0
  42. package/node_modules/@playdrop/config/dist/src/server/logging.d.ts +3 -0
  43. package/node_modules/@playdrop/config/dist/src/server/logging.d.ts.map +1 -0
  44. package/node_modules/@playdrop/config/dist/src/server/logging.js +46 -0
  45. package/node_modules/@playdrop/config/dist/test/deployment.test.d.ts +2 -0
  46. package/node_modules/@playdrop/config/dist/test/deployment.test.d.ts.map +1 -0
  47. package/node_modules/@playdrop/config/dist/test/deployment.test.js +74 -0
  48. package/node_modules/@playdrop/config/dist/test/logging.test.d.ts +2 -0
  49. package/node_modules/@playdrop/config/dist/test/logging.test.d.ts.map +1 -0
  50. package/node_modules/@playdrop/config/dist/test/logging.test.js +17 -0
  51. package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
  52. package/node_modules/@playdrop/config/package.json +14 -2
  53. package/node_modules/@playdrop/types/dist/api.d.ts +27 -10
  54. package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
  55. package/node_modules/@playdrop/types/dist/api.js +11 -0
  56. package/node_modules/@playdrop/types/dist/asset-pack.d.ts +1 -0
  57. package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
  58. package/node_modules/@playdrop/types/dist/asset.d.ts +34 -4
  59. package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
  60. package/node_modules/@playdrop/types/dist/asset.js +20 -1
  61. package/node_modules/@playdrop/types/dist/version.d.ts +3 -1
  62. package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
  63. package/node_modules/@playdrop/types/dist/version.js +2 -0
  64. package/node_modules/@playdrop/types/package.json +1 -1
  65. package/node_modules/@playdrop/vox-three/package.json +1 -1
  66. package/package.json +3 -3
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDeployRole = parseDeployRole;
4
+ exports.parseDeploySlot = parseDeploySlot;
5
+ exports.parsePublicSurface = parsePublicSurface;
6
+ exports.resolveDeployRole = resolveDeployRole;
7
+ exports.resolveDeploySlot = resolveDeploySlot;
8
+ exports.resolvePublicSurface = resolvePublicSurface;
9
+ exports.resolveEnvironmentName = resolveEnvironmentName;
10
+ exports.resolveSeoIndexingMode = resolveSeoIndexingMode;
11
+ exports.resolveWebOrigin = resolveWebOrigin;
12
+ exports.resolveApiOrigin = resolveApiOrigin;
13
+ exports.resolveRealtimeOrigin = resolveRealtimeOrigin;
14
+ exports.resolveAiOrigin = resolveAiOrigin;
15
+ exports.resolveStructuredLogFields = resolveStructuredLogFields;
16
+ const DEPLOY_ROLE_VALUES = new Set(['prod', 'preview']);
17
+ const DEPLOY_SLOT_VALUES = new Set(['blue', 'green']);
18
+ const PUBLIC_SURFACE_VALUES = new Set(['prod', 'preview', 'blue', 'green']);
19
+ function normalizeValue(value) {
20
+ if (typeof value !== 'string') {
21
+ return null;
22
+ }
23
+ const normalized = value.trim().toLowerCase();
24
+ return normalized.length > 0 ? normalized : null;
25
+ }
26
+ function normalizeOrigin(value) {
27
+ return value.trim().replace(/\/+$/, '');
28
+ }
29
+ function buildDefaultOrigin(params) {
30
+ const { servicePrefix, surface, websocket = false } = params;
31
+ const protocol = websocket ? 'wss' : 'https';
32
+ const host = surface === 'prod'
33
+ ? servicePrefix ? `${servicePrefix}.playdrop.ai` : 'www.playdrop.ai'
34
+ : servicePrefix
35
+ ? `${servicePrefix}.${surface}.playdrop.ai`
36
+ : `${surface}.playdrop.ai`;
37
+ return `${protocol}://${host}`;
38
+ }
39
+ function parseReleaseBuild(value) {
40
+ const parsed = Number(value);
41
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
42
+ }
43
+ function parseDeployRole(value) {
44
+ const normalized = normalizeValue(value);
45
+ if (!normalized || !DEPLOY_ROLE_VALUES.has(normalized)) {
46
+ return null;
47
+ }
48
+ return normalized;
49
+ }
50
+ function parseDeploySlot(value) {
51
+ const normalized = normalizeValue(value);
52
+ if (!normalized || !DEPLOY_SLOT_VALUES.has(normalized)) {
53
+ return null;
54
+ }
55
+ return normalized;
56
+ }
57
+ function parsePublicSurface(value) {
58
+ const normalized = normalizeValue(value);
59
+ if (!normalized || !PUBLIC_SURFACE_VALUES.has(normalized)) {
60
+ return null;
61
+ }
62
+ return normalized;
63
+ }
64
+ function resolveDeployRole(env = process.env) {
65
+ return parseDeployRole(env['PLAYDROP_DEPLOY_ROLE'])
66
+ ?? (env['NODE_ENV'] === 'production' ? 'prod' : 'preview');
67
+ }
68
+ function resolveDeploySlot(env = process.env) {
69
+ return parseDeploySlot(env['PLAYDROP_SLOT']);
70
+ }
71
+ function resolvePublicSurface(env = process.env) {
72
+ const explicit = parsePublicSurface(env['PLAYDROP_PUBLIC_SURFACE']);
73
+ if (explicit) {
74
+ return explicit;
75
+ }
76
+ return resolveDeployRole(env) === 'preview' ? 'preview' : 'prod';
77
+ }
78
+ function resolveEnvironmentName(env = process.env) {
79
+ const explicit = typeof env['PLAYDROP_ENVIRONMENT'] === 'string' ? env['PLAYDROP_ENVIRONMENT'].trim() : '';
80
+ if (explicit.length > 0) {
81
+ return explicit;
82
+ }
83
+ const nodeEnv = typeof env['NODE_ENV'] === 'string' ? env['NODE_ENV'].trim() : '';
84
+ return nodeEnv.length > 0 ? nodeEnv : 'development';
85
+ }
86
+ function resolveSeoIndexingMode(env = process.env) {
87
+ const explicit = normalizeValue(env['PLAYDROP_SEO_INDEXING']);
88
+ if (explicit === 'public') {
89
+ return 'public';
90
+ }
91
+ if (explicit === 'private') {
92
+ return 'private';
93
+ }
94
+ if (explicit === 'noindex') {
95
+ return 'noindex';
96
+ }
97
+ return resolveDeployRole(env) === 'prod' ? 'public' : 'noindex';
98
+ }
99
+ function resolveWebOrigin(env = process.env) {
100
+ const explicit = typeof env['PLAYDROP_PUBLIC_ORIGIN'] === 'string' ? env['PLAYDROP_PUBLIC_ORIGIN'].trim() : '';
101
+ if (explicit.length > 0) {
102
+ return normalizeOrigin(explicit);
103
+ }
104
+ const legacy = typeof env['PLAYDROP_WEB_BASE_URL'] === 'string' ? env['PLAYDROP_WEB_BASE_URL'].trim() : '';
105
+ if (legacy.length > 0) {
106
+ return normalizeOrigin(legacy);
107
+ }
108
+ return buildDefaultOrigin({ surface: resolvePublicSurface(env) });
109
+ }
110
+ function resolveApiOrigin(env = process.env) {
111
+ const explicit = typeof env['PLAYDROP_API_BASE_URL'] === 'string' ? env['PLAYDROP_API_BASE_URL'].trim() : '';
112
+ if (explicit.length > 0) {
113
+ return normalizeOrigin(explicit);
114
+ }
115
+ return buildDefaultOrigin({ servicePrefix: 'api', surface: resolvePublicSurface(env) });
116
+ }
117
+ function resolveRealtimeOrigin(env = process.env) {
118
+ const explicit = typeof env['PLAYDROP_REALTIME_BASE_URL'] === 'string' ? env['PLAYDROP_REALTIME_BASE_URL'].trim() : '';
119
+ if (explicit.length > 0) {
120
+ return normalizeOrigin(explicit);
121
+ }
122
+ return buildDefaultOrigin({ servicePrefix: 'play', surface: resolvePublicSurface(env), websocket: true });
123
+ }
124
+ function resolveAiOrigin(env = process.env) {
125
+ const explicit = typeof env['PLAYDROP_AI_BASE_URL'] === 'string' ? env['PLAYDROP_AI_BASE_URL'].trim() : '';
126
+ if (explicit.length > 0) {
127
+ return normalizeOrigin(explicit);
128
+ }
129
+ return buildDefaultOrigin({ servicePrefix: 'ai', surface: resolvePublicSurface(env) });
130
+ }
131
+ function resolveStructuredLogFields(service, env = process.env) {
132
+ const releaseVersion = typeof env['PLAYDROP_RELEASE_VERSION'] === 'string' && env['PLAYDROP_RELEASE_VERSION'].trim().length > 0
133
+ ? env['PLAYDROP_RELEASE_VERSION'].trim()
134
+ : typeof env['NEXT_PUBLIC_PLAYDROP_RELEASE_VERSION'] === 'string' && env['NEXT_PUBLIC_PLAYDROP_RELEASE_VERSION'].trim().length > 0
135
+ ? env['NEXT_PUBLIC_PLAYDROP_RELEASE_VERSION'].trim()
136
+ : '0.0.0';
137
+ const buildNumber = parseReleaseBuild(env['PLAYDROP_BUILD_NUMBER'] ?? env['NEXT_PUBLIC_PLAYDROP_BUILD_NUMBER']);
138
+ const slot = resolveDeploySlot(env);
139
+ return {
140
+ environment: resolveEnvironmentName(env),
141
+ slot: slot ?? 'none',
142
+ service,
143
+ release_version: releaseVersion,
144
+ build_number: buildNumber,
145
+ deploy_role: resolveDeployRole(env),
146
+ public_surface: resolvePublicSurface(env),
147
+ };
148
+ }
@@ -1,10 +1,69 @@
1
- import type { FastifyRequest } from 'fastify';
1
+ import { Writable } from 'node:stream';
2
+ import type { FastifyInstance, FastifyLoggerOptions, FastifyReply, FastifyRequest, FastifyServerOptions, RawServerDefault } from 'fastify';
2
3
  import type { ClientErrorResponseBody, ClientRuntimeInfo, ClientValidator, ClientValidationFailure, ClientGuard, NormalizedClientRuntimeInfo } from '../types';
3
4
  declare module 'fastify' {
4
5
  interface FastifyRequest {
5
6
  clientRuntime?: NormalizedClientRuntimeInfo;
7
+ requestLogContext?: {
8
+ userId?: string;
9
+ roomId?: string;
10
+ };
6
11
  }
7
12
  }
13
+ export declare function setRequestLogContext(request: FastifyRequest, input: {
14
+ userId?: string | number | null;
15
+ roomId?: string | number | null;
16
+ }): void;
17
+ export declare function buildFastifyLogger(service: string): (FastifyLoggerOptions<RawServerDefault, FastifyRequest<import("fastify").RouteGenericInterface, RawServerDefault, import("http").IncomingMessage, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown, import("fastify").FastifyBaseLogger, import("fastify/types/type-provider").ResolveFastifyRequestType<import("fastify").FastifyTypeProviderDefault, import("fastify").FastifySchema, import("fastify").RouteGenericInterface>>, FastifyReply<import("fastify").RouteGenericInterface, RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>> & {
18
+ base: Record<string, unknown>;
19
+ messageKey: string;
20
+ formatters: {
21
+ level(label: string): {
22
+ level: string;
23
+ };
24
+ };
25
+ timestamp: () => string;
26
+ stream?: Writable;
27
+ }) | {
28
+ stream: Writable;
29
+ serializers?: {
30
+ req?: (req: FastifyRequest<import("fastify").RouteGenericInterface, RawServerDefault, import("http").IncomingMessage, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown, import("fastify").FastifyBaseLogger, import("fastify/types/type-provider").ResolveFastifyRequestType<import("fastify").FastifyTypeProviderDefault, import("fastify").FastifySchema, import("fastify").RouteGenericInterface>>) => {
31
+ method?: string;
32
+ url?: string;
33
+ version?: string;
34
+ host?: string;
35
+ remoteAddress?: string;
36
+ remotePort?: number;
37
+ [key: string]: unknown;
38
+ };
39
+ err?: (err: import("fastify").FastifyError) => {
40
+ type: string;
41
+ message: string;
42
+ stack: string;
43
+ [key: string]: unknown;
44
+ };
45
+ res?: (res: import("fastify/types/logger").ResSerializerReply<RawServerDefault, FastifyReply<import("fastify").RouteGenericInterface, RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>>) => {
46
+ statusCode?: string | number;
47
+ [key: string]: unknown;
48
+ };
49
+ };
50
+ level?: string;
51
+ file?: string;
52
+ genReqId?: (req: FastifyRequest<import("fastify").RouteGenericInterface, RawServerDefault, import("http").IncomingMessage, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown, import("fastify").FastifyBaseLogger, import("fastify/types/type-provider").ResolveFastifyRequestType<import("fastify").FastifyTypeProviderDefault, import("fastify").FastifySchema, import("fastify").RouteGenericInterface>>) => string;
53
+ base: Record<string, unknown>;
54
+ messageKey: string;
55
+ formatters: {
56
+ level(label: string): {
57
+ level: string;
58
+ };
59
+ };
60
+ timestamp: () => string;
61
+ };
62
+ export declare function buildFastifyServerOptions(params: {
63
+ service: string;
64
+ bodyLimit?: number;
65
+ }): FastifyServerOptions<RawServerDefault>;
66
+ export declare function registerStructuredRequestLogging(app: FastifyInstance): void;
8
67
  export declare function readClientHeaders(request: FastifyRequest): ClientRuntimeInfo;
9
68
  export declare function formatClientError(failure: ClientValidationFailure): ClientErrorResponseBody;
10
69
  export declare function buildClientGuard(reader?: (request: FastifyRequest) => ClientRuntimeInfo, validator?: ClientValidator, formatter?: (failure: ClientValidationFailure) => ClientErrorResponseBody): ClientGuard;
@@ -1 +1 @@
1
- {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../../src/server/fastify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAM5D,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,WAAW,EACX,2BAA2B,EAC5B,MAAM,UAAU,CAAC;AAElB,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,aAAa,CAAC,EAAE,2BAA2B,CAAC;KAC7C;CACF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,CAiB5E;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,uBAAuB,GAC/B,uBAAuB,CAkEzB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,GAAE,CAAC,OAAO,EAAE,cAAc,KAAK,iBAAqC,EAC1E,SAAS,GAAE,eAA2C,EACtD,SAAS,GAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,uBAA2C,GAC3F,WAAW,CAkBb;AAED,eAAO,MAAM,qBAAqB,aAAqB,CAAC"}
1
+ {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../../src/server/fastify.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,oBAAoB,EAEpB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAQjB,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,WAAW,EACX,2BAA2B,EAC5B,MAAM,UAAU,CAAC;AAElB,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,aAAa,CAAC,EAAE,2BAA2B,CAAC;QAC5C,iBAAiB,CAAC,EAAE;YAClB,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;KACH;CACF;AAUD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE;IACL,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACjC,GACA,IAAI,CAUN;AAgBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM;UAYxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACjB,MAAM;gBACN;QACV,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;YACpB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;KACH;eACU,MAAM,MAAM;aACd,QAAQ;;;;;kBATiB,CAAC;eAAoB,CAAA;mBACtC,CAAC;gBACf,CAAC;yBACK,CAAC;sBACQ,CAAC;;;;;;;;;;sBAaG,CAAC;;;;;;;UAhBjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACjB,MAAM;gBACN;QACV,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;YACpB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;KACH;eACU,MAAM,MAAM;EAW1B;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,CAiBzC;AAED,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAsC3E;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,CAiB5E;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,uBAAuB,GAC/B,uBAAuB,CAkEzB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,GAAE,CAAC,OAAO,EAAE,cAAc,KAAK,iBAAqC,EAC1E,SAAS,GAAE,eAA2C,EACtD,SAAS,GAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,uBAA2C,GAC3F,WAAW,CAkBb;AAED,eAAO,MAAM,qBAAqB,aAAqB,CAAC"}
@@ -1,10 +1,129 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.ensureSupportedClient = void 0;
7
+ exports.setRequestLogContext = setRequestLogContext;
8
+ exports.buildFastifyLogger = buildFastifyLogger;
9
+ exports.buildFastifyServerOptions = buildFastifyServerOptions;
10
+ exports.registerStructuredRequestLogging = registerStructuredRequestLogging;
4
11
  exports.readClientHeaders = readClientHeaders;
5
12
  exports.formatClientError = formatClientError;
6
13
  exports.buildClientGuard = buildClientGuard;
14
+ const node_crypto_1 = require("node:crypto");
15
+ const node_fs_1 = __importDefault(require("node:fs"));
16
+ const node_path_1 = __importDefault(require("node:path"));
17
+ const node_stream_1 = require("node:stream");
7
18
  const index_1 = require("../index");
19
+ const logging_1 = require("./logging");
20
+ function normalizeLogContextValue(value) {
21
+ if (value === undefined || value === null) {
22
+ return undefined;
23
+ }
24
+ const normalized = `${value}`.trim();
25
+ return normalized.length > 0 ? normalized : undefined;
26
+ }
27
+ function setRequestLogContext(request, input) {
28
+ const nextUserId = normalizeLogContextValue(input.userId);
29
+ const nextRoomId = normalizeLogContextValue(input.roomId);
30
+ const current = request.requestLogContext ?? {};
31
+ request.requestLogContext = {
32
+ ...(current.userId ? { userId: current.userId } : {}),
33
+ ...(current.roomId ? { roomId: current.roomId } : {}),
34
+ ...(nextUserId ? { userId: nextUserId } : {}),
35
+ ...(nextRoomId ? { roomId: nextRoomId } : {}),
36
+ };
37
+ }
38
+ function createStructuredLogMirrorStream(logFilePath) {
39
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(logFilePath), { recursive: true });
40
+ const fileStream = node_fs_1.default.createWriteStream(logFilePath, { flags: 'a' });
41
+ return new node_stream_1.Writable({
42
+ write(chunk, _encoding, callback) {
43
+ process.stdout.write(chunk);
44
+ fileStream.write(chunk, callback);
45
+ },
46
+ final(callback) {
47
+ fileStream.end(callback);
48
+ },
49
+ });
50
+ }
51
+ function buildFastifyLogger(service) {
52
+ const logger = {
53
+ level: process.env['LOG_LEVEL']?.trim() || 'info',
54
+ base: (0, index_1.resolveStructuredLogFields)(service),
55
+ messageKey: 'message',
56
+ formatters: {
57
+ level(label) {
58
+ return { level: label };
59
+ },
60
+ },
61
+ timestamp: () => `,"timestamp":"${new Date().toISOString()}"`,
62
+ };
63
+ const logFilePath = (0, logging_1.resolveStructuredLogFilePath)(service);
64
+ if (!logFilePath) {
65
+ return logger;
66
+ }
67
+ return {
68
+ ...logger,
69
+ stream: createStructuredLogMirrorStream(logFilePath),
70
+ };
71
+ }
72
+ function buildFastifyServerOptions(params) {
73
+ return {
74
+ logger: buildFastifyLogger(params.service),
75
+ disableRequestLogging: true,
76
+ requestIdHeader: 'x-request-id',
77
+ genReqId(request) {
78
+ const explicit = request.headers['x-request-id'];
79
+ if (typeof explicit === 'string' && explicit.trim().length > 0) {
80
+ return explicit.trim();
81
+ }
82
+ if (Array.isArray(explicit) && typeof explicit[0] === 'string' && explicit[0].trim().length > 0) {
83
+ return explicit[0].trim();
84
+ }
85
+ return (0, node_crypto_1.randomUUID)();
86
+ },
87
+ ...(typeof params.bodyLimit === 'number' ? { bodyLimit: params.bodyLimit } : {}),
88
+ };
89
+ }
90
+ function registerStructuredRequestLogging(app) {
91
+ app.addHook('onRequest', async (request, reply) => {
92
+ reply.header('x-request-id', request.id);
93
+ request.log.info({
94
+ request_id: request.id,
95
+ method: request.method,
96
+ path: request.url,
97
+ host: request.hostname,
98
+ remote_ip: request.ip,
99
+ }, 'request_started');
100
+ });
101
+ app.addHook('onError', async (request, _reply, error) => {
102
+ const context = request.requestLogContext ?? {};
103
+ request.log.error({
104
+ err: error,
105
+ request_id: request.id,
106
+ method: request.method,
107
+ path: request.url,
108
+ user_id: context.userId,
109
+ room_id: context.roomId,
110
+ }, 'request_failed');
111
+ });
112
+ app.addHook('onResponse', async (request, reply) => {
113
+ const context = request.requestLogContext ?? {};
114
+ const elapsedMs = typeof reply.elapsedTime === 'number' ? Math.round(reply.elapsedTime) : undefined;
115
+ request.log.info({
116
+ request_id: request.id,
117
+ method: request.method,
118
+ path: request.url,
119
+ route: request.routeOptions.url,
120
+ status_code: reply.statusCode,
121
+ duration_ms: elapsedMs,
122
+ user_id: context.userId,
123
+ room_id: context.roomId,
124
+ }, 'request_completed');
125
+ });
126
+ }
8
127
  function readClientHeaders(request) {
9
128
  const headers = request.headers || {};
10
129
  const getHeader = (name) => {
@@ -0,0 +1,3 @@
1
+ export declare function resolveStructuredLogFilePath(service: string, env?: NodeJS.ProcessEnv): string | null;
2
+ export declare function createStructuredLogEmitter(service: string, env?: NodeJS.ProcessEnv): (payload: Record<string, unknown>, stream?: 'stdout' | 'stderr') => void;
3
+ //# sourceMappingURL=logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/server/logging.ts"],"names":[],"mappings":"AAYA,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,IAAI,CAMf;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAqB1E"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveStructuredLogFilePath = resolveStructuredLogFilePath;
7
+ exports.createStructuredLogEmitter = createStructuredLogEmitter;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ function normalizeStructuredLogDir(env = process.env) {
11
+ const value = env['PLAYDROP_STRUCTURED_LOG_DIR'];
12
+ if (typeof value !== 'string') {
13
+ return null;
14
+ }
15
+ const normalized = value.trim();
16
+ return normalized.length > 0 ? normalized : null;
17
+ }
18
+ function resolveStructuredLogFilePath(service, env = process.env) {
19
+ const directory = normalizeStructuredLogDir(env);
20
+ if (!directory) {
21
+ return null;
22
+ }
23
+ return path_1.default.join(directory, `${service}.jsonl`);
24
+ }
25
+ function createStructuredLogEmitter(service, env = process.env) {
26
+ const logFilePath = resolveStructuredLogFilePath(service, env);
27
+ const fileStream = logFilePath
28
+ ? fs_1.default.createWriteStream(logFilePath, { flags: 'a' })
29
+ : null;
30
+ return (payload, stream = 'stdout') => {
31
+ const normalizedPayload = Object.prototype.hasOwnProperty.call(payload, 'timestamp')
32
+ ? payload
33
+ : {
34
+ timestamp: new Date().toISOString(),
35
+ ...payload,
36
+ };
37
+ const line = `${JSON.stringify(normalizedPayload)}\n`;
38
+ if (stream === 'stderr') {
39
+ process.stderr.write(line);
40
+ }
41
+ else {
42
+ process.stdout.write(line);
43
+ }
44
+ fileStream?.write(line);
45
+ };
46
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=deployment.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment.test.d.ts","sourceRoot":"","sources":["../../test/deployment.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = __importDefault(require("node:test"));
8
+ const deployment_1 = require("../src/deployment");
9
+ (0, node_test_1.default)('deploy role parsing stays strict', () => {
10
+ strict_1.default.equal((0, deployment_1.parseDeployRole)('prod'), 'prod');
11
+ strict_1.default.equal((0, deployment_1.parseDeployRole)('preview'), 'preview');
12
+ strict_1.default.equal((0, deployment_1.parseDeployRole)('blue'), null);
13
+ strict_1.default.equal((0, deployment_1.parseDeployRole)(undefined), null);
14
+ });
15
+ (0, node_test_1.default)('deploy slot parsing stays strict', () => {
16
+ strict_1.default.equal((0, deployment_1.parseDeploySlot)('blue'), 'blue');
17
+ strict_1.default.equal((0, deployment_1.parseDeploySlot)('green'), 'green');
18
+ strict_1.default.equal((0, deployment_1.parseDeploySlot)('prod'), null);
19
+ });
20
+ (0, node_test_1.default)('prod defaults resolve to public production origins', () => {
21
+ const env = { NODE_ENV: 'production' };
22
+ strict_1.default.equal((0, deployment_1.resolveDeployRole)(env), 'prod');
23
+ strict_1.default.equal((0, deployment_1.resolvePublicSurface)(env), 'prod');
24
+ strict_1.default.equal((0, deployment_1.resolveWebOrigin)(env), 'https://www.playdrop.ai');
25
+ strict_1.default.equal((0, deployment_1.resolveApiOrigin)(env), 'https://api.playdrop.ai');
26
+ strict_1.default.equal((0, deployment_1.resolveAiOrigin)(env), 'https://ai.playdrop.ai');
27
+ strict_1.default.equal((0, deployment_1.resolveRealtimeOrigin)(env), 'wss://play.playdrop.ai');
28
+ strict_1.default.equal((0, deployment_1.resolveSeoIndexingMode)(env), 'public');
29
+ strict_1.default.equal((0, deployment_1.isBackgroundWorkEnabled)(env), true);
30
+ });
31
+ (0, node_test_1.default)('preview defaults resolve to preview origins and noindex seo', () => {
32
+ const env = {
33
+ NODE_ENV: 'production',
34
+ PLAYDROP_DEPLOY_ROLE: 'preview',
35
+ PLAYDROP_SLOT: 'green',
36
+ };
37
+ strict_1.default.equal((0, deployment_1.resolveDeployRole)(env), 'preview');
38
+ strict_1.default.equal((0, deployment_1.resolvePublicSurface)(env), 'preview');
39
+ strict_1.default.equal((0, deployment_1.resolveWebOrigin)(env), 'https://preview.playdrop.ai');
40
+ strict_1.default.equal((0, deployment_1.resolveApiOrigin)(env), 'https://api.preview.playdrop.ai');
41
+ strict_1.default.equal((0, deployment_1.resolveAiOrigin)(env), 'https://ai.preview.playdrop.ai');
42
+ strict_1.default.equal((0, deployment_1.resolveRealtimeOrigin)(env), 'wss://play.preview.playdrop.ai');
43
+ strict_1.default.equal((0, deployment_1.resolveSeoIndexingMode)(env), 'noindex');
44
+ strict_1.default.equal((0, deployment_1.isBackgroundWorkEnabled)(env), false);
45
+ });
46
+ (0, node_test_1.default)('explicit origin overrides win over derived defaults', () => {
47
+ const env = {
48
+ PLAYDROP_PUBLIC_ORIGIN: 'https://blue.playdrop.ai/',
49
+ PLAYDROP_API_BASE_URL: 'https://api.blue.playdrop.ai/',
50
+ PLAYDROP_AI_BASE_URL: 'https://ai.blue.playdrop.ai/',
51
+ PLAYDROP_REALTIME_BASE_URL: 'wss://play.blue.playdrop.ai/ws/',
52
+ PLAYDROP_PUBLIC_SURFACE: 'blue',
53
+ };
54
+ strict_1.default.equal((0, deployment_1.resolvePublicSurface)(env), 'blue');
55
+ strict_1.default.equal((0, deployment_1.resolveWebOrigin)(env), 'https://blue.playdrop.ai');
56
+ strict_1.default.equal((0, deployment_1.resolveApiOrigin)(env), 'https://api.blue.playdrop.ai');
57
+ strict_1.default.equal((0, deployment_1.resolveAiOrigin)(env), 'https://ai.blue.playdrop.ai');
58
+ strict_1.default.equal((0, deployment_1.resolveRealtimeOrigin)(env), 'wss://play.blue.playdrop.ai/ws');
59
+ });
60
+ (0, node_test_1.default)('structured log fields include phase 1 deploy metadata', () => {
61
+ const fields = (0, deployment_1.resolveStructuredLogFields)('api-server', {
62
+ NODE_ENV: 'production',
63
+ PLAYDROP_DEPLOY_ROLE: 'preview',
64
+ PLAYDROP_SLOT: 'green',
65
+ PLAYDROP_PUBLIC_SURFACE: 'preview',
66
+ });
67
+ strict_1.default.equal(fields.environment, 'production');
68
+ strict_1.default.equal(fields.slot, 'green');
69
+ strict_1.default.equal(fields.service, 'api-server');
70
+ strict_1.default.equal(fields.deploy_role, 'preview');
71
+ strict_1.default.equal(fields.public_surface, 'preview');
72
+ strict_1.default.match(fields.release_version, /^\d+\.\d+\.\d+$/);
73
+ strict_1.default.equal(typeof fields.build_number, 'number');
74
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=logging.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.test.d.ts","sourceRoot":"","sources":["../../test/logging.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = __importDefault(require("node:test"));
8
+ const logging_1 = require("../src/server/logging");
9
+ (0, node_test_1.default)('structured log file path is disabled without an explicit directory', () => {
10
+ strict_1.default.equal((0, logging_1.resolveStructuredLogFilePath)('api-server', {}), null);
11
+ });
12
+ (0, node_test_1.default)('structured log file path resolves to a per-service jsonl file', () => {
13
+ const filePath = (0, logging_1.resolveStructuredLogFilePath)('api-server', {
14
+ PLAYDROP_STRUCTURED_LOG_DIR: '/var/log/playdrop',
15
+ });
16
+ strict_1.default.equal(filePath, '/var/log/playdrop/api-server.jsonl');
17
+ });