@mayson-org/inject-script 1.0.21 → 1.0.24

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/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAkEA,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DtE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAyEA,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DtE"}
package/dist/cli.js CHANGED
@@ -12,15 +12,16 @@ Usage:
12
12
  Options:
13
13
  --dir <path> Target project root (default: cwd)
14
14
  --type <type> watermark | ascii | metadata | pwa | all
15
- (default: watermark + ascii + pwa)
15
+ (default: watermark + ascii + metadata + pwa)
16
+ --url <url> Set MAYSON_APP_BASE_URL
16
17
  --no-pwa Skip PWA artifacts even when included by default / --type=all
17
18
  --dry-run Preview without writing files
18
19
  --help, -h Show help
19
20
 
20
- Watermark gating (inject-time):
21
+ Watermark & Metadata gating (inject-time):
21
22
  Fetches generated-app-metadata when MAYSON_WORKSPACE_ID, MAYSON_COLLECTION_ID,
22
- MAYSON_API_BASE_URL, and MAYSON_WEB_TOKEN are set. Injects watermark only when
23
- show_remix_pill is true; bakes enable_remix into the generated component.
23
+ MAYSON_API_BASE_URL, and MAYSON_WEB_TOKEN are set. Injects watermark and
24
+ metadata API route handler (/api/randomeapipath) with cookie caching.
24
25
 
25
26
  PWA (default on):
26
27
  Writes MaysonServiceWorkerRegister + MaysonInstallPrompt beside the layout,
@@ -31,7 +32,7 @@ PWA (default on):
31
32
  function parseArgs(argv) {
32
33
  const options = {
33
34
  projectRoot: process.cwd(),
34
- types: ['watermark', 'ascii', 'pwa'],
35
+ types: ['watermark', 'ascii', 'metadata', 'pwa'],
35
36
  dryRun: false,
36
37
  pwa: true,
37
38
  help: false,
@@ -59,8 +60,16 @@ function parseArgs(argv) {
59
60
  else if (arg === '--dir' && argv[i + 1]) {
60
61
  options.projectRoot = path.resolve(argv[++i]);
61
62
  }
63
+ else if (arg.startsWith('--url=')) {
64
+ const url = arg.split('=')[1];
65
+ process.env.MAYSON_APP_BASE_URL = url;
66
+ }
67
+ else if (arg === '--url' && argv[i + 1]) {
68
+ process.env.MAYSON_APP_BASE_URL = argv[++i];
69
+ }
62
70
  else {
63
- throw new Error(`unknown argument: ${arg}`);
71
+ // Gracefully ignore unknown arguments instead of crashing CLI
72
+ console.log(`[mayson] ignoring unknown argument: ${arg}`);
64
73
  }
65
74
  }
66
75
  return options;
@@ -19,6 +19,9 @@ export type PluginGenerateContext = {
19
19
  backgroundColor: string;
20
20
  description: string;
21
21
  };
22
+ metadata?: {
23
+ apiRoutePath?: string;
24
+ };
22
25
  };
23
26
  export interface ComponentGeneratorOptions {
24
27
  outputDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,WAAW,GACX,OAAO,GACP,UAAU,GACV,KAAK,GACL,KAAK,CAAC;AAEV,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,iEAAiE;AACjE,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE;QACV,aAAa,EAAE,OAAO,CAAC;QACvB,WAAW,EAAE,OAAO,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,sBAAsB,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACpC,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,cAAc,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,qBAAqB,KAAK,MAAM,CAAC;IAC7D,+DAA+D;IAC/D,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,mBAAmB,CAAC;CACpE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,WAAW,GACX,OAAO,GACP,UAAU,GACV,KAAK,GACL,KAAK,CAAC;AAEV,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,iEAAiE;AACjE,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE;QACV,aAAa,EAAE,OAAO,CAAC;QACvB,WAAW,EAAE,OAAO,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,sBAAsB,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACpC,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,cAAc,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,qBAAqB,KAAK,MAAM,CAAC;IAC7D,+DAA+D;IAC/D,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,mBAAmB,CAAC;CACpE"}
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export type { MaysonEnvConfig } from './shared/config.js';
10
10
  export { fetchGeneratedAppMetadata, resolveMaysonConfig, shouldFetchGeneratedAppMetadata, } from './shared/generated-app-metadata.js';
11
11
  export { watermarkPlugin, buildMaysonWatermarkSource, } from './plugins/watermark/index.js';
12
12
  export { asciiPlugin, buildMaysonAsciiSource, } from './plugins/ascii/index.js';
13
- export { metadataPlugin, handleMetadataApiRoute, generateMetadataApiRouteSource, injectMetadataApiRoute, METADATA_COOKIE_NAME, DEFAULT_COOKIE_MAX_AGE, } from './plugins/metadata/index.js';
13
+ export { metadataPlugin, handleMetadataApiRoute, generateMetadataApiRouteSource, injectMetadataApiRoute, generateRandomApiSubpath, resolveMetadataApiSubpath, METADATA_COOKIE_NAME, DEFAULT_COOKIE_MAX_AGE, } from './plugins/metadata/index.js';
14
14
  export type { MetadataApiResponse, MaysonRealtimeStats } from './plugins/metadata/index.js';
15
15
  export { pwaPlugin, injectPwaProject, buildMaysonServiceWorkerRegisterSource, buildMaysonInstallPromptSource, buildManifestSource, buildSwJsSource, patchLayoutPwaMetadata, } from './plugins/pwa/index.js';
16
16
  export { BUILD_WITH_LOVE_ASCII, MAYSON_LETTER_ASCII, } from './shared/ascii-art.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAEf,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAChF,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,+BAA+B,GAChC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,eAAe,EACf,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,WAAW,EACX,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,8BAA8B,EAC9B,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC5F,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,sCAAsC,EACtC,8BAA8B,EAC9B,mBAAmB,EACnB,eAAe,EACf,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EACf,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AA4EF;;;GAGG;AACH,wBAAsB,aAAa,CACjC,WAAW,GAAE,MAAsB,EACnC,cAAc,GAAE,aAAa,EAAE,GAAG,oBAAoC,EACtE,SAAS,GAAE,OAAe,GACzB,OAAO,CAAC,cAAc,CAAC,CA+GzB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAEf,MAAM,iBAAiB,CAAC;AAKzB,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAChF,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,+BAA+B,GAChC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,eAAe,EACf,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,WAAW,EACX,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,8BAA8B,EAC9B,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC5F,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,sCAAsC,EACtC,8BAA8B,EAC9B,mBAAmB,EACnB,eAAe,EACf,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EACf,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AA4EF;;;GAGG;AACH,wBAAsB,aAAa,CACjC,WAAW,GAAE,MAAsB,EACnC,cAAc,GAAE,aAAa,EAAE,GAAG,oBAAoC,EACtE,SAAS,GAAE,OAAe,GACzB,OAAO,CAAC,cAAc,CAAC,CAmHzB"}
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { generateComponents } from './core/generators.js';
4
4
  import { injectComponentsIntoLayout } from './core/injector.js';
5
5
  import { deleteGeneratedComponentFile, removeComponentFromLayout, } from './core/remove-component.js';
6
6
  import { plugins } from './plugins/index.js';
7
+ import { resolveMetadataApiSubpath } from './plugins/metadata/index.js';
7
8
  import { resolveMaysonConfig } from './shared/generated-app-metadata.js';
8
9
  export { findRootLayout } from './core/find-root-layout.js';
9
10
  export { generateComponents } from './core/generators.js';
@@ -14,10 +15,10 @@ export { loadMaysonEnvConfig } from './shared/config.js';
14
15
  export { fetchGeneratedAppMetadata, resolveMaysonConfig, shouldFetchGeneratedAppMetadata, } from './shared/generated-app-metadata.js';
15
16
  export { watermarkPlugin, buildMaysonWatermarkSource, } from './plugins/watermark/index.js';
16
17
  export { asciiPlugin, buildMaysonAsciiSource, } from './plugins/ascii/index.js';
17
- export { metadataPlugin, handleMetadataApiRoute, generateMetadataApiRouteSource, injectMetadataApiRoute, METADATA_COOKIE_NAME, DEFAULT_COOKIE_MAX_AGE, } from './plugins/metadata/index.js';
18
+ export { metadataPlugin, handleMetadataApiRoute, generateMetadataApiRouteSource, injectMetadataApiRoute, generateRandomApiSubpath, resolveMetadataApiSubpath, METADATA_COOKIE_NAME, DEFAULT_COOKIE_MAX_AGE, } from './plugins/metadata/index.js';
18
19
  export { pwaPlugin, injectPwaProject, buildMaysonServiceWorkerRegisterSource, buildMaysonInstallPromptSource, buildManifestSource, buildSwJsSource, patchLayoutPwaMetadata, } from './plugins/pwa/index.js';
19
20
  export { BUILD_WITH_LOVE_ASCII, MAYSON_LETTER_ASCII, } from './shared/ascii-art.js';
20
- const DEFAULT_TYPES = ['watermark', 'ascii', 'pwa'];
21
+ const DEFAULT_TYPES = ['watermark', 'ascii', 'metadata', 'pwa'];
21
22
  const ALL_TYPES = ['watermark', 'ascii', 'metadata', 'pwa'];
22
23
  function normalizeArgs(typesOrOptions, dryRunArg) {
23
24
  if (Array.isArray(typesOrOptions)) {
@@ -94,6 +95,7 @@ export async function runAutoInject(projectRoot = process.cwd(), typesOrOptions
94
95
  messages,
95
96
  };
96
97
  }
98
+ const apiSubpath = resolveMetadataApiSubpath(projectRoot, layoutPath);
97
99
  const context = {
98
100
  watermark: {
99
101
  showRemixPill: config.showRemixPill,
@@ -107,6 +109,9 @@ export async function runAutoInject(projectRoot = process.cwd(), typesOrOptions
107
109
  backgroundColor: '#ffffff',
108
110
  description: 'Generated by Mayson',
109
111
  },
112
+ metadata: {
113
+ apiRoutePath: `/api/${apiSubpath}`,
114
+ },
110
115
  };
111
116
  const isTypeScript = layoutPath.endsWith('.tsx') || layoutPath.endsWith('.ts');
112
117
  const targetDir = path.dirname(layoutPath);
@@ -1,6 +1,7 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { handleMetadataApiRoute, METADATA_COOKIE_NAME, generateMetadataApiRouteSource, } from '../api-handler.js';
4
+ import { generateRandomApiSubpath } from '../inject-api-route.js';
4
5
  describe('Metadata API Route & Cookie Caching', () => {
5
6
  it('returns cache MISS on initial request without cookie', async () => {
6
7
  const req = new Request('http://localhost:3000/api/randomeapipath', {
@@ -38,9 +39,17 @@ describe('Metadata API Route & Cookie Caching', () => {
38
39
  assert.equal(data.data.enableRemix, false);
39
40
  assert.equal(data.data.websiteTitle, 'Test App');
40
41
  });
41
- it('generates valid App Router route handler source code', () => {
42
+ it('generates valid self-contained App Router route handler source code', () => {
42
43
  const source = generateMetadataApiRouteSource();
43
- assert.ok(source.includes("import { handleMetadataApiRoute } from '@mayson-org/inject-script'"));
44
- assert.ok(source.includes('export async function GET(request: Request)'));
44
+ assert.ok(!source.includes('@mayson-org/inject-script'));
45
+ assert.ok(source.includes('export async function GET(req: Request)'));
46
+ assert.ok(source.includes('mayson_metadata_cache'));
47
+ });
48
+ it('generates random API route subpaths starting with mayson-', () => {
49
+ const subpath1 = generateRandomApiSubpath();
50
+ const subpath2 = generateRandomApiSubpath();
51
+ assert.ok(subpath1.startsWith('mayson-'));
52
+ assert.ok(subpath2.startsWith('mayson-'));
53
+ assert.notEqual(subpath1, subpath2);
45
54
  });
46
55
  });
@@ -12,7 +12,8 @@ export type MetadataApiResponse = {
12
12
  */
13
13
  export declare function handleMetadataApiRoute(req: Request): Promise<Response>;
14
14
  /**
15
- * Generate Next.js App Router Route Handler code for /api/randomeapipath/route.ts
15
+ * Generate Next.js App Router Route Handler standalone source code for /api/randomeapipath/route.ts
16
+ * Self-contained without external package dependencies.
16
17
  */
17
18
  export declare function generateMetadataApiRouteSource(): string;
18
19
  //# sourceMappingURL=api-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/plugins/metadata/api-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAC5D,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,GAAG,aAAa,GAAG,cAAc,CAAC,CAAC;IAC9E,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAiBF;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsD5E;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAWvD"}
1
+ {"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/plugins/metadata/api-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAC5D,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,GAAG,aAAa,GAAG,cAAc,CAAC,CAAC;IAC9E,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAiBF;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsD5E;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAkIvD"}
@@ -71,17 +71,137 @@ export async function handleMetadataApiRoute(req) {
71
71
  });
72
72
  }
73
73
  /**
74
- * Generate Next.js App Router Route Handler code for /api/randomeapipath/route.ts
74
+ * Generate Next.js App Router Route Handler standalone source code for /api/randomeapipath/route.ts
75
+ * Self-contained without external package dependencies.
75
76
  */
76
77
  export function generateMetadataApiRouteSource() {
77
- return `import { handleMetadataApiRoute } from '@mayson-org/inject-script';
78
+ return `const METADATA_COOKIE_NAME = 'mayson_metadata_cache';
79
+ const DEFAULT_COOKIE_MAX_AGE = 300; // 5 minutes
78
80
 
79
- export async function GET(request: Request) {
80
- return handleMetadataApiRoute(request);
81
+ function readEnv(key: string): string {
82
+ return process.env[key]?.trim() ?? '';
81
83
  }
82
84
 
83
- export async function POST(request: Request) {
84
- return handleMetadataApiRoute(request);
85
+ function parseCookies(cookieHeader: string | null | undefined): Record<string, string> {
86
+ if (!cookieHeader) return {};
87
+ const cookies: Record<string, string> = {};
88
+ for (const pair of cookieHeader.split(';')) {
89
+ const [key, ...val] = pair.trim().split('=');
90
+ if (key) {
91
+ cookies[key] = decodeURIComponent(val.join('='));
92
+ }
93
+ }
94
+ return cookies;
95
+ }
96
+
97
+ async function resolveMetadataConfig() {
98
+ const workspaceId = readEnv('MAYSON_WORKSPACE_ID');
99
+ const collectionId = readEnv('MAYSON_COLLECTION_ID') || readEnv('NEXT_PUBLIC_MAYSON_COLLECTION_ID');
100
+ const apiBaseUrl = readEnv('MAYSON_API_BASE_URL');
101
+ const webToken = readEnv('MAYSON_WEB_TOKEN');
102
+ const websiteTitle = readEnv('MAYSON_WEBSITE_TITLE') || readEnv('NEXT_PUBLIC_MAYSON_WEBSITE_TITLE');
103
+
104
+ const baseConfig = {
105
+ showRemixPill: true,
106
+ enableRemix: true,
107
+ websiteTitle: websiteTitle || '',
108
+ };
109
+
110
+ if (!workspaceId || !collectionId || !apiBaseUrl || !webToken) {
111
+ return baseConfig;
112
+ }
113
+
114
+ try {
115
+ const cleanBase = apiBaseUrl.replace(/\\/$/, '');
116
+ const url = \`\${cleanBase}/sigma/web/v1/generated-app-metadata/workspaces/\${encodeURIComponent(workspaceId)}/collections/\${encodeURIComponent(collectionId)}\`;
117
+
118
+ const res = await fetch(url, {
119
+ headers: {
120
+ Accept: 'application/json',
121
+ 'M-Web-Token': webToken,
122
+ },
123
+ signal: AbortSignal.timeout(5000),
124
+ });
125
+
126
+ if (res.status === 404 || !res.ok) {
127
+ return baseConfig;
128
+ }
129
+
130
+ const data = await res.json();
131
+ if (data?.value && typeof data.value === 'object') {
132
+ const show = data.value.show_remix_pill;
133
+ const remix = data.value.enable_remix;
134
+ if (typeof show === 'boolean' || show === 'true' || show === 'false') {
135
+ baseConfig.showRemixPill = show === true || show === 'true';
136
+ }
137
+ if (typeof remix === 'boolean' || remix === 'true' || remix === 'false') {
138
+ baseConfig.enableRemix = remix === true || remix === 'true';
139
+ }
140
+ if (typeof data.value.website_title === 'string' && data.value.website_title.trim()) {
141
+ baseConfig.websiteTitle = data.value.website_title.trim();
142
+ }
143
+ }
144
+ } catch {
145
+ // Return baseConfig on error
146
+ }
147
+
148
+ return baseConfig;
149
+ }
150
+
151
+ export async function GET(req: Request) {
152
+ const cookieHeader = req.headers.get('cookie');
153
+ const cookies = parseCookies(cookieHeader);
154
+
155
+ const cachedValue = cookies[METADATA_COOKIE_NAME];
156
+ if (cachedValue) {
157
+ try {
158
+ const parsed = JSON.parse(cachedValue);
159
+ if (typeof parsed.showRemixPill === 'boolean') {
160
+ return new Response(
161
+ JSON.stringify({
162
+ success: true,
163
+ cached: true,
164
+ data: parsed,
165
+ timestamp: Date.now(),
166
+ }),
167
+ {
168
+ status: 200,
169
+ headers: {
170
+ 'Content-Type': 'application/json',
171
+ 'X-Mayson-Cache': 'HIT',
172
+ },
173
+ },
174
+ );
175
+ }
176
+ } catch {
177
+ // Invalid cache content
178
+ }
179
+ }
180
+
181
+ const data = await resolveMetadataConfig();
182
+ const serializedData = encodeURIComponent(JSON.stringify(data));
183
+ const setCookieHeader = \`\${METADATA_COOKIE_NAME}=\${serializedData}; Path=/; Max-Age=\${DEFAULT_COOKIE_MAX_AGE}; SameSite=Lax; HttpOnly\`;
184
+
185
+ return new Response(
186
+ JSON.stringify({
187
+ success: true,
188
+ cached: false,
189
+ data,
190
+ timestamp: Date.now(),
191
+ }),
192
+ {
193
+ status: 200,
194
+ headers: {
195
+ 'Content-Type': 'application/json',
196
+ 'Set-Cookie': setCookieHeader,
197
+ 'X-Mayson-Cache': 'MISS',
198
+ },
199
+ },
200
+ );
201
+ }
202
+
203
+ export async function POST(req: Request) {
204
+ return GET(req);
85
205
  }
86
206
  `;
87
207
  }
@@ -1,11 +1,12 @@
1
- import type { MaysonPlugin } from '../../core/types.js';
1
+ import type { MaysonPlugin, PluginGenerateContext } from '../../core/types.js';
2
2
  export { handleMetadataApiRoute, generateMetadataApiRouteSource, METADATA_COOKIE_NAME, DEFAULT_COOKIE_MAX_AGE, } from './api-handler.js';
3
3
  export type { MetadataApiResponse } from './api-handler.js';
4
- export { injectMetadataApiRoute, DEFAULT_METADATA_API_ROUTE_PATH, } from './inject-api-route.js';
4
+ export { injectMetadataApiRoute, generateRandomApiSubpath, resolveMetadataApiSubpath, } from './inject-api-route.js';
5
5
  export type MaysonRealtimeStats = {
6
6
  showRemixPill: boolean;
7
7
  enableRemix: boolean;
8
8
  websiteTitle: string;
9
9
  };
10
+ export declare function buildMaysonMetadataSource(context?: PluginGenerateContext): string;
10
11
  export declare const metadataPlugin: MaysonPlugin;
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/metadata/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EACL,sBAAsB,EACtB,8BAA8B,EAC9B,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,sBAAsB,EACtB,+BAA+B,GAChC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAuDF,eAAO,MAAM,cAAc,EAAE,YAK5B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/metadata/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG/E,OAAO,EACL,sBAAsB,EACtB,8BAA8B,EAC9B,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAsDjF;AAED,eAAO,MAAM,cAAc,EAAE,YAK5B,CAAC"}
@@ -1,7 +1,9 @@
1
1
  import { injectMetadataApiRoute } from './inject-api-route.js';
2
2
  export { handleMetadataApiRoute, generateMetadataApiRouteSource, METADATA_COOKIE_NAME, DEFAULT_COOKIE_MAX_AGE, } from './api-handler.js';
3
- export { injectMetadataApiRoute, DEFAULT_METADATA_API_ROUTE_PATH, } from './inject-api-route.js';
4
- const METADATA_SOURCE = `'use client';
3
+ export { injectMetadataApiRoute, generateRandomApiSubpath, resolveMetadataApiSubpath, } from './inject-api-route.js';
4
+ export function buildMaysonMetadataSource(context) {
5
+ const apiRoute = context?.metadata?.apiRoutePath ?? '/api/mayson-metadata';
6
+ return `'use client';
5
7
 
6
8
  import React, { useEffect, useState } from 'react';
7
9
 
@@ -11,7 +13,7 @@ export type MaysonRealtimeStats = {
11
13
  websiteTitle: string;
12
14
  };
13
15
 
14
- export function MaysonMetadata({ apiRoute = '/api/randomeapipath' }: { apiRoute?: string }) {
16
+ export function MaysonMetadata({ apiRoute = ${JSON.stringify(apiRoute)} }: { apiRoute?: string }) {
15
17
  const [stats, setStats] = useState<MaysonRealtimeStats | null>(null);
16
18
 
17
19
  useEffect(() => {
@@ -53,9 +55,10 @@ export function MaysonMetadata({ apiRoute = '/api/randomeapipath' }: { apiRoute?
53
55
  );
54
56
  }
55
57
  `;
58
+ }
56
59
  export const metadataPlugin = {
57
60
  type: 'metadata',
58
61
  name: 'MaysonMetadata',
59
- generateSource: () => METADATA_SOURCE,
62
+ generateSource: (context) => buildMaysonMetadataSource(context),
60
63
  injectProject: (context) => injectMetadataApiRoute(context),
61
64
  };
@@ -1,7 +1,12 @@
1
1
  import type { ProjectInjectContext, ProjectInjectResult } from '../../core/types.js';
2
- export declare const DEFAULT_METADATA_API_ROUTE_PATH = "app/api/randomeapipath/route.ts";
2
+ export declare function generateRandomApiSubpath(): string;
3
+ export declare function findAppDir(projectRoot: string, layoutPath?: string): string;
3
4
  /**
4
- * Inject the metadata API route handler (/api/randomeapipath) into the project workspace.
5
+ :// Locate existing mayson API route subpath if present, or generate a new random subpath.
6
+ */
7
+ export declare function resolveMetadataApiSubpath(projectRoot: string, layoutPath?: string, overrideSubpath?: string): string;
8
+ /**
9
+ * Inject the metadata API route handler (/api/<random-subpath>) into the project workspace.
5
10
  */
6
11
  export declare function injectMetadataApiRoute(context: ProjectInjectContext & {
7
12
  routeSubpath?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"inject-api-route.d.ts","sourceRoot":"","sources":["../../../src/plugins/metadata/inject-api-route.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGrF,eAAO,MAAM,+BAA+B,oCAAoC,CAAC;AAEjF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,oBAAoB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD,mBAAmB,CAkDrB"}
1
+ {"version":3,"file":"inject-api-route.d.ts","sourceRoot":"","sources":["../../../src/plugins/metadata/inject-api-route.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAGrF,wBAAgB,wBAAwB,IAAI,MAAM,CAOjD;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ3E;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CA8BR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,oBAAoB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD,mBAAmB,CAiDrB"}
@@ -1,24 +1,68 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { generateMetadataApiRouteSource } from './api-handler.js';
4
- export const DEFAULT_METADATA_API_ROUTE_PATH = 'app/api/randomeapipath/route.ts';
4
+ export function generateRandomApiSubpath() {
5
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
6
+ let randomSlug = '';
7
+ for (let i = 0; i < 8; i++) {
8
+ randomSlug += chars.charAt(Math.floor(Math.random() * chars.length));
9
+ }
10
+ return `mayson-${randomSlug}`;
11
+ }
12
+ export function findAppDir(projectRoot, layoutPath) {
13
+ if (layoutPath && layoutPath.includes(`${path.sep}src${path.sep}app`)) {
14
+ return path.join(projectRoot, 'src', 'app');
15
+ }
16
+ if (!fs.existsSync(path.join(projectRoot, 'app')) && fs.existsSync(path.join(projectRoot, 'src', 'app'))) {
17
+ return path.join(projectRoot, 'src', 'app');
18
+ }
19
+ return path.join(projectRoot, 'app');
20
+ }
21
+ /**
22
+ :// Locate existing mayson API route subpath if present, or generate a new random subpath.
23
+ */
24
+ export function resolveMetadataApiSubpath(projectRoot, layoutPath, overrideSubpath) {
25
+ if (overrideSubpath && overrideSubpath.trim()) {
26
+ return overrideSubpath.trim().replace(/^\/api\//, '');
27
+ }
28
+ const appDir = findAppDir(projectRoot, layoutPath);
29
+ const apiDir = path.join(appDir, 'api');
30
+ if (fs.existsSync(apiDir)) {
31
+ try {
32
+ const entries = fs.readdirSync(apiDir, { withFileTypes: true });
33
+ for (const entry of entries) {
34
+ if (entry.isDirectory()) {
35
+ // Check if directory starts with mayson- or is randomeapipath
36
+ if (entry.name.startsWith('mayson-') || entry.name === 'randomeapipath') {
37
+ const hasRoute = fs.existsSync(path.join(apiDir, entry.name, 'route.ts')) ||
38
+ fs.existsSync(path.join(apiDir, entry.name, 'route.js'));
39
+ if (hasRoute) {
40
+ return entry.name;
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ catch {
47
+ // Ignore reading error
48
+ }
49
+ }
50
+ return generateRandomApiSubpath();
51
+ }
5
52
  /**
6
- * Inject the metadata API route handler (/api/randomeapipath) into the project workspace.
53
+ * Inject the metadata API route handler (/api/<random-subpath>) into the project workspace.
7
54
  */
8
55
  export function injectMetadataApiRoute(context) {
9
- const { projectRoot, layoutPath, dryRun = false, routeSubpath = 'randomeapipath' } = context;
56
+ const { projectRoot, layoutPath, dryRun = false } = context;
10
57
  const messages = [];
11
58
  const injectedComponents = [];
12
59
  const skippedComponents = [];
13
- // Determine App Router root directory (app/ or src/app/)
14
- let appDir = path.join(projectRoot, 'app');
15
- if (layoutPath && layoutPath.includes(`${path.sep}src${path.sep}app`)) {
16
- appDir = path.join(projectRoot, 'src', 'app');
17
- }
18
- else if (!fs.existsSync(appDir) && fs.existsSync(path.join(projectRoot, 'src', 'app'))) {
19
- appDir = path.join(projectRoot, 'src', 'app');
20
- }
21
- const apiRouteDir = path.join(appDir, 'api', routeSubpath);
60
+ const subpath = context.routeSubpath ??
61
+ (context.context?.metadata?.apiRoutePath
62
+ ? context.context.metadata.apiRoutePath.replace(/^\/api\//, '')
63
+ : resolveMetadataApiSubpath(projectRoot, layoutPath));
64
+ const appDir = findAppDir(projectRoot, layoutPath);
65
+ const apiRouteDir = path.join(appDir, 'api', subpath);
22
66
  const isTs = layoutPath ? layoutPath.endsWith('.ts') || layoutPath.endsWith('.tsx') : true;
23
67
  const fileName = isTs ? 'route.ts' : 'route.js';
24
68
  const filePath = path.join(apiRouteDir, fileName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mayson-org/inject-script",
3
- "version": "1.0.21",
3
+ "version": "1.0.24",
4
4
  "description": "CLI and library to inject Mayson watermark, ascii, and PWA into Next.js App Router layouts.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",