@c15t/cli 1.4.4 → 1.5.0-canary-20250722085128

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.mjs CHANGED
@@ -779,26 +779,6 @@ function generateEnvExampleContent(pkg) {
779
779
  const envVarName = getEnvVarName(pkg);
780
780
  return `\n# c15t Configuration\n${envVarName}=https://your-instance.c15t.dev\n`;
781
781
  }
782
- const HTML_TAG_REGEX = /<html[^>]*>([\s\S]*)<\/html>/;
783
- const BODY_TAG_REGEX = /<body[^>]*>([\s\S]*)<\/body>/;
784
- const BODY_OPENING_TAG_REGEX = /<body[^>]*>/;
785
- const HTML_CONTENT_REGEX = /([\s\S]*<\/html>)/;
786
- function findLayoutFile(project, projectRoot) {
787
- const layoutPatterns = [
788
- '**/app.tsx',
789
- '**/App.tsx',
790
- '**/app/app.tsx',
791
- '**/src/app/app.tsx',
792
- '**/layout.tsx',
793
- '**/Layout.tsx',
794
- '**/app/layout.tsx',
795
- '**/src/app/layout.tsx'
796
- ];
797
- for (const pattern of layoutPatterns){
798
- const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
799
- if (files.length > 0) return files[0];
800
- }
801
- }
802
782
  function generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs) {
803
783
  switch(mode){
804
784
  case 'c15t':
@@ -832,12 +812,43 @@ function generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs) {
832
812
  }`;
833
813
  }
834
814
  }
835
- function updateImports(layoutFile, packageName, mode) {
836
- const requiredImports = [
837
- 'ConsentManagerProvider',
815
+ function getBaseImports() {
816
+ return [
838
817
  'CookieBanner',
839
818
  'ConsentManagerDialog'
840
819
  ];
820
+ }
821
+ function getCustomModeImports() {
822
+ return [
823
+ {
824
+ namedImports: [
825
+ 'createCustomHandlers'
826
+ ],
827
+ moduleSpecifier: './consent-handlers'
828
+ }
829
+ ];
830
+ }
831
+ const HTML_TAG_REGEX = /<html[^>]*>([\s\S]*)<\/html>/;
832
+ const BODY_TAG_REGEX = /<body[^>]*>([\s\S]*)<\/body>/;
833
+ const BODY_OPENING_TAG_REGEX = /<body[^>]*>/;
834
+ const HTML_CONTENT_REGEX = /([\s\S]*<\/html>)/;
835
+ function findAppLayoutFile(project, projectRoot) {
836
+ const layoutPatterns = [
837
+ 'app/layout.tsx',
838
+ 'src/app/layout.tsx',
839
+ 'app/layout.ts',
840
+ 'src/app/layout.ts'
841
+ ];
842
+ for (const pattern of layoutPatterns){
843
+ const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
844
+ if (files.length > 0) return files[0];
845
+ }
846
+ }
847
+ function updateAppImports(layoutFile, packageName, mode) {
848
+ const requiredImports = [
849
+ 'ConsentManagerProvider',
850
+ ...getBaseImports()
851
+ ];
841
852
  let hasC15tImport = false;
842
853
  for (const importDecl of layoutFile.getImportDeclarations())if (importDecl.getModuleSpecifierValue() === packageName) {
843
854
  hasC15tImport = true;
@@ -850,14 +861,9 @@ function updateImports(layoutFile, packageName, mode) {
850
861
  namedImports: requiredImports,
851
862
  moduleSpecifier: packageName
852
863
  });
853
- if ('custom' === mode) layoutFile.addImportDeclaration({
854
- namedImports: [
855
- 'createCustomHandlers'
856
- ],
857
- moduleSpecifier: './consent-handlers'
858
- });
864
+ if ('custom' === mode) for (const customImport of getCustomModeImports())layoutFile.addImportDeclaration(customImport);
859
865
  }
860
- function wrapJsxContent(originalJsx, optionsText) {
866
+ function wrapAppJsxContent(originalJsx, optionsText) {
861
867
  const hasHtmlTag = originalJsx.includes('<html') || originalJsx.includes('</html>');
862
868
  const hasBodyTag = originalJsx.includes('<body') || originalJsx.includes('</body>');
863
869
  const providerWrapper = (content)=>`
@@ -886,9 +892,9 @@ function wrapJsxContent(originalJsx, optionsText) {
886
892
  }
887
893
  return providerWrapper(originalJsx);
888
894
  }
889
- async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
895
+ async function updateAppLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
890
896
  const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
891
- const layoutFile = findLayoutFile(project, projectRoot);
897
+ const layoutFile = findAppLayoutFile(project, projectRoot);
892
898
  if (!layoutFile) return {
893
899
  updated: false,
894
900
  filePath: null,
@@ -901,7 +907,7 @@ async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFil
901
907
  filePath: layoutFile.getFilePath(),
902
908
  alreadyModified: true
903
909
  };
904
- updateImports(layoutFile, pkg, mode);
910
+ updateAppImports(layoutFile, pkg, mode);
905
911
  const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
906
912
  const returnStatement = layoutFile.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
907
913
  if (!returnStatement) return {
@@ -916,7 +922,7 @@ async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFil
916
922
  alreadyModified: false
917
923
  };
918
924
  const originalJsx = expression.getText();
919
- const newJsx = wrapJsxContent(originalJsx, optionsText);
925
+ const newJsx = wrapAppJsxContent(originalJsx, optionsText);
920
926
  returnStatement.replaceWithText(`return ${newJsx}`);
921
927
  await layoutFile.save();
922
928
  return {
@@ -925,6 +931,284 @@ async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFil
925
931
  alreadyModified: false
926
932
  };
927
933
  }
934
+ function findPagesAppFile(project, projectRoot) {
935
+ const appPatterns = [
936
+ 'pages/_app.tsx',
937
+ 'pages/_app.ts',
938
+ 'src/pages/_app.tsx',
939
+ 'src/pages/_app.ts'
940
+ ];
941
+ for (const pattern of appPatterns){
942
+ const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
943
+ if (files.length > 0) return files[0];
944
+ }
945
+ }
946
+ function updatePagesImports(appFile, packageName, mode) {
947
+ const requiredImports = [
948
+ 'ConsentManagerProvider',
949
+ ...getBaseImports()
950
+ ];
951
+ const pagesModuleSpecifier = `${packageName}/pages`;
952
+ let hasC15tImport = false;
953
+ for (const importDecl of appFile.getImportDeclarations())if (importDecl.getModuleSpecifierValue() === pagesModuleSpecifier) {
954
+ hasC15tImport = true;
955
+ const namedImports = importDecl.getNamedImports().map((i)=>i.getName());
956
+ const missingImports = requiredImports.filter((imp)=>!namedImports.includes(imp));
957
+ if (missingImports.length > 0) importDecl.addNamedImports(missingImports);
958
+ break;
959
+ }
960
+ if (!hasC15tImport) appFile.addImportDeclaration({
961
+ namedImports: requiredImports,
962
+ moduleSpecifier: pagesModuleSpecifier
963
+ });
964
+ if ('custom' === mode) for (const customImport of getCustomModeImports())appFile.addImportDeclaration(customImport);
965
+ }
966
+ function wrapPagesJsxContent(originalJsx, optionsText) {
967
+ const trimmedJsx = originalJsx.trim();
968
+ const hasParentheses = trimmedJsx.startsWith('(') && trimmedJsx.endsWith(')');
969
+ const cleanJsx = hasParentheses ? trimmedJsx.slice(1, -1).trim() : originalJsx;
970
+ const wrappedContent = `
971
+ <ConsentManagerProvider
972
+ initialData={pageProps.initialC15TData}
973
+ options={${optionsText}}
974
+ >
975
+ <CookieBanner />
976
+ <ConsentManagerDialog />
977
+ ${cleanJsx}
978
+ </ConsentManagerProvider>
979
+ `;
980
+ return `(${wrappedContent})`;
981
+ }
982
+ function addServerSideDataComment(appFile, backendURL, useEnvFile, proxyNextjs) {
983
+ const existingComments = appFile.getLeadingCommentRanges();
984
+ let urlExample;
985
+ urlExample = proxyNextjs ? "'/api/c15t'" : useEnvFile ? 'process.env.NEXT_PUBLIC_C15T_URL!' : `'${backendURL || 'https://your-instance.c15t.dev'}'`;
986
+ const serverSideComment = `/**
987
+ * Note: To get the initial server-side data on other pages, add this to each page:
988
+ *
989
+ * import { withInitialC15TData } from '@c15t/nextjs/pages';
990
+ *
991
+ * export const getServerSideProps = withInitialC15TData(${urlExample});
992
+ *
993
+ * This will automatically pass initialC15TData to pageProps.initialC15TData
994
+ */`;
995
+ const hasServerSideComment = existingComments.some((comment)=>comment.getText().includes('withInitialC15TData'));
996
+ if (!hasServerSideComment) appFile.insertText(0, `${serverSideComment}\n\n`);
997
+ }
998
+ function updateAppComponentTyping(appFile) {
999
+ const exportAssignment = appFile.getExportAssignment(()=>true);
1000
+ if (!exportAssignment) return;
1001
+ const declaration = exportAssignment.getExpression();
1002
+ if (!declaration) return;
1003
+ const text = declaration.getText();
1004
+ if (text.includes('pageProps') && !text.includes('AppProps')) {
1005
+ const hasAppPropsImport = appFile.getImportDeclarations().some((importDecl)=>'next/app' === importDecl.getModuleSpecifierValue() && importDecl.getNamedImports().some((namedImport)=>'AppProps' === namedImport.getName()));
1006
+ if (!hasAppPropsImport) appFile.addImportDeclaration({
1007
+ namedImports: [
1008
+ 'AppProps'
1009
+ ],
1010
+ moduleSpecifier: 'next/app'
1011
+ });
1012
+ }
1013
+ }
1014
+ async function updatePagesLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
1015
+ const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
1016
+ const appFile = findPagesAppFile(project, projectRoot);
1017
+ if (!appFile) return {
1018
+ updated: false,
1019
+ filePath: null,
1020
+ alreadyModified: false
1021
+ };
1022
+ const existingImports = appFile.getImportDeclarations();
1023
+ const pagesModuleSpecifier = `${pkg}/pages`;
1024
+ const hasPackageImport = existingImports.some((importDecl)=>importDecl.getModuleSpecifierValue() === pagesModuleSpecifier);
1025
+ if (hasPackageImport) return {
1026
+ updated: false,
1027
+ filePath: appFile.getFilePath(),
1028
+ alreadyModified: true
1029
+ };
1030
+ updatePagesImports(appFile, pkg, mode);
1031
+ updateAppComponentTyping(appFile);
1032
+ addServerSideDataComment(appFile, backendURL, useEnvFile, proxyNextjs);
1033
+ const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
1034
+ const returnStatement = appFile.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
1035
+ if (!returnStatement) return {
1036
+ updated: false,
1037
+ filePath: appFile.getFilePath(),
1038
+ alreadyModified: false
1039
+ };
1040
+ const expression = returnStatement.getExpression();
1041
+ if (!expression) return {
1042
+ updated: false,
1043
+ filePath: appFile.getFilePath(),
1044
+ alreadyModified: false
1045
+ };
1046
+ const originalJsx = expression.getText();
1047
+ const newJsx = wrapPagesJsxContent(originalJsx, optionsText);
1048
+ returnStatement.replaceWithText(`return ${newJsx}`);
1049
+ await appFile.save();
1050
+ return {
1051
+ updated: true,
1052
+ filePath: appFile.getFilePath(),
1053
+ alreadyModified: false
1054
+ };
1055
+ }
1056
+ function detectNextJsStructure(projectRoot) {
1057
+ const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
1058
+ const appLayoutPatterns = [
1059
+ 'app/layout.tsx',
1060
+ 'src/app/layout.tsx',
1061
+ 'app/layout.ts',
1062
+ 'src/app/layout.ts'
1063
+ ];
1064
+ for (const pattern of appLayoutPatterns){
1065
+ const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1066
+ if (files.length > 0) return 'app';
1067
+ }
1068
+ const pagesAppPatterns = [
1069
+ 'pages/_app.tsx',
1070
+ 'pages/_app.ts',
1071
+ 'src/pages/_app.tsx',
1072
+ 'src/pages/_app.ts'
1073
+ ];
1074
+ for (const pattern of pagesAppPatterns){
1075
+ const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1076
+ if (files.length > 0) return 'pages';
1077
+ }
1078
+ return null;
1079
+ }
1080
+ async function updateNextLayout(options) {
1081
+ const structureType = detectNextJsStructure(options.projectRoot);
1082
+ if (!structureType) return {
1083
+ updated: false,
1084
+ filePath: null,
1085
+ alreadyModified: false,
1086
+ structureType: null
1087
+ };
1088
+ let result;
1089
+ result = 'app' === structureType ? await updateAppLayout(options) : await updatePagesLayout(options);
1090
+ return {
1091
+ ...result,
1092
+ structureType
1093
+ };
1094
+ }
1095
+ function updateGenericReactImports(layoutFile, packageName, mode) {
1096
+ const requiredImports = [
1097
+ 'ConsentManagerProvider',
1098
+ ...getBaseImports()
1099
+ ];
1100
+ let hasPackageImport = false;
1101
+ for (const importDecl of layoutFile.getImportDeclarations())if (importDecl.getModuleSpecifierValue() === packageName) {
1102
+ hasPackageImport = true;
1103
+ const namedImports = importDecl.getNamedImports().map((i)=>i.getName());
1104
+ const missingImports = requiredImports.filter((imp)=>!namedImports.includes(imp));
1105
+ if (missingImports.length > 0) importDecl.addNamedImports(missingImports);
1106
+ break;
1107
+ }
1108
+ if (!hasPackageImport) layoutFile.addImportDeclaration({
1109
+ namedImports: requiredImports,
1110
+ moduleSpecifier: packageName
1111
+ });
1112
+ if ('custom' === mode) for (const customImport of getCustomModeImports())layoutFile.addImportDeclaration(customImport);
1113
+ }
1114
+ function updateGenericReactJsx(layoutFile, mode, backendURL, useEnvFile, proxyNextjs) {
1115
+ const functionDeclarations = layoutFile.getFunctions();
1116
+ const variableDeclarations = layoutFile.getVariableDeclarations();
1117
+ for (const func of functionDeclarations){
1118
+ const returnStatement = func.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
1119
+ if (returnStatement) return wrapReturnStatement(returnStatement, mode, backendURL, useEnvFile, proxyNextjs);
1120
+ }
1121
+ for (const varDecl of variableDeclarations){
1122
+ const initializer = varDecl.getInitializer();
1123
+ if (initializer) {
1124
+ const returnStatement = initializer.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
1125
+ if (returnStatement) return wrapReturnStatement(returnStatement, mode, backendURL, useEnvFile, proxyNextjs);
1126
+ }
1127
+ }
1128
+ return false;
1129
+ }
1130
+ function wrapReturnStatement(returnStatement, mode, backendURL, useEnvFile, proxyNextjs) {
1131
+ const expression = returnStatement.getExpression();
1132
+ if (!expression) return false;
1133
+ const originalJsx = expression.getText();
1134
+ const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
1135
+ const newJsx = `(
1136
+ <ConsentManagerProvider options={${optionsText}}>
1137
+ <CookieBanner />
1138
+ <ConsentManagerDialog />
1139
+ ${originalJsx}
1140
+ </ConsentManagerProvider>
1141
+ )`;
1142
+ returnStatement.replaceWithText(`return ${newJsx}`);
1143
+ return true;
1144
+ }
1145
+ async function updateGenericReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
1146
+ const layoutPatterns = [
1147
+ 'app.tsx',
1148
+ 'App.tsx',
1149
+ 'app.jsx',
1150
+ 'App.jsx',
1151
+ 'src/app.tsx',
1152
+ 'src/App.tsx',
1153
+ 'src/app.jsx',
1154
+ 'src/App.jsx',
1155
+ 'src/app/app.tsx',
1156
+ 'src/app/App.tsx',
1157
+ 'src/app/app.jsx',
1158
+ 'src/app/App.jsx'
1159
+ ];
1160
+ const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
1161
+ let layoutFile;
1162
+ for (const pattern of layoutPatterns)try {
1163
+ const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
1164
+ if (files.length > 0) {
1165
+ layoutFile = files[0];
1166
+ break;
1167
+ }
1168
+ } catch {}
1169
+ if (!layoutFile) return {
1170
+ updated: false,
1171
+ filePath: null,
1172
+ alreadyModified: false
1173
+ };
1174
+ const existingImports = layoutFile.getImportDeclarations();
1175
+ const hasPackageImport = existingImports.some((importDecl)=>importDecl.getModuleSpecifierValue() === pkg);
1176
+ if (hasPackageImport) return {
1177
+ updated: false,
1178
+ filePath: layoutFile.getFilePath(),
1179
+ alreadyModified: true
1180
+ };
1181
+ try {
1182
+ updateGenericReactImports(layoutFile, pkg, mode);
1183
+ const updated = updateGenericReactJsx(layoutFile, mode, backendURL, useEnvFile, proxyNextjs);
1184
+ if (updated) {
1185
+ await layoutFile.save();
1186
+ return {
1187
+ updated: true,
1188
+ filePath: layoutFile.getFilePath(),
1189
+ alreadyModified: false
1190
+ };
1191
+ }
1192
+ return {
1193
+ updated: false,
1194
+ filePath: layoutFile.getFilePath(),
1195
+ alreadyModified: false
1196
+ };
1197
+ } catch (error) {
1198
+ throw new Error(`Failed to update generic React layout: ${error instanceof Error ? error.message : String(error)}`);
1199
+ }
1200
+ }
1201
+ async function updateReactLayout(options) {
1202
+ if ('@c15t/nextjs' === options.pkg) {
1203
+ const nextResult = await updateNextLayout(options);
1204
+ if (nextResult.structureType) return {
1205
+ updated: nextResult.updated,
1206
+ filePath: nextResult.filePath,
1207
+ alreadyModified: nextResult.alreadyModified
1208
+ };
1209
+ }
1210
+ return updateGenericReactLayout(options);
1211
+ }
928
1212
  async function updateNextConfig({ projectRoot, backendURL, useEnvFile }) {
929
1213
  const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
930
1214
  const configFile = findNextConfigFile(project, projectRoot);
@@ -0,0 +1,7 @@
1
+ export { updateReactLayout } from './layout';
2
+ export { updateNextLayout } from './next';
3
+ export { updateAppLayout } from './next/app/layout';
4
+ export { updatePagesLayout } from './next/pages/layout';
5
+ export { generateOptionsText, getBaseImports, getCustomModeImports, } from './shared/options';
6
+ export type { AvailablePackages } from '../../context/framework-detection';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/onboarding/templates/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EACN,mBAAmB,EACnB,cAAc,EACd,oBAAoB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC"}
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Templates module for generating configuration files
3
- * These functions generate template configuration content for different storage modes
3
+ * This module now serves as a wrapper that routes to the appropriate implementation
4
+ * based on the detected project structure (App Directory vs Pages Directory)
4
5
  */
5
6
  import type { AvailablePackages } from '../../context/framework-detection';
6
7
  interface UpdateReactLayoutOptions {
@@ -11,16 +12,7 @@ interface UpdateReactLayoutOptions {
11
12
  pkg: AvailablePackages;
12
13
  proxyNextjs?: boolean;
13
14
  }
14
- /**
15
- * Updates or creates a React layout file with ConsentManagerProvider
16
- *
17
- * @param projectRoot - The root directory of the project
18
- * @param mode - The storage mode ('c15t', 'offline', or 'custom')
19
- * @param backendURL - URL for the c15t backend/API (for 'c15t' mode)
20
- * @param useEnvFile - Whether to use environment variable for backendURL
21
- * @returns Information about the update
22
- */
23
- export declare function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs, }: UpdateReactLayoutOptions): Promise<{
15
+ export declare function updateReactLayout(options: UpdateReactLayoutOptions): Promise<{
24
16
  updated: boolean;
25
17
  filePath: string | null;
26
18
  alreadyModified: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/onboarding/templates/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAOvE,UAAU,wBAAwB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAyKD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,EACvC,WAAW,EACX,IAAI,EACJ,GAAG,EACH,UAAU,EACV,UAAU,EACV,WAAW,GACX,EAAE,wBAAwB,GAAG,OAAO,CAAC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CA2DD"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/onboarding/templates/layout.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAQvE,UAAU,wBAAwB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAwQD,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CAiBD"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * App Directory layout template generator
3
+ * Handles updating Next.js App Directory layout files with ConsentManagerProvider
4
+ */
5
+ import type { AvailablePackages } from '../../../../context/framework-detection';
6
+ interface UpdateAppLayoutOptions {
7
+ projectRoot: string;
8
+ mode: string;
9
+ backendURL?: string;
10
+ useEnvFile?: boolean;
11
+ pkg: AvailablePackages;
12
+ proxyNextjs?: boolean;
13
+ }
14
+ export declare function updateAppLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs, }: UpdateAppLayoutOptions): Promise<{
15
+ updated: boolean;
16
+ filePath: string | null;
17
+ alreadyModified: boolean;
18
+ }>;
19
+ export {};
20
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/onboarding/templates/next/app/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAYvE,UAAU,sBAAsB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAkHD,wBAAsB,eAAe,CAAC,EACrC,WAAW,EACX,IAAI,EACJ,GAAG,EACH,UAAU,EACV,UAAU,EACV,WAAW,GACX,EAAE,sBAAsB,GAAG,OAAO,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CA2DD"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Unified Next.js template handler
3
+ * Detects whether the project uses App Directory or Pages Directory
4
+ * and routes to the appropriate implementation
5
+ */
6
+ import type { AvailablePackages } from '../../../context/framework-detection';
7
+ interface UpdateNextLayoutOptions {
8
+ projectRoot: string;
9
+ mode: string;
10
+ backendURL?: string;
11
+ useEnvFile?: boolean;
12
+ pkg: AvailablePackages;
13
+ proxyNextjs?: boolean;
14
+ }
15
+ type NextStructure = 'app' | 'pages' | null;
16
+ export declare function updateNextLayout(options: UpdateNextLayoutOptions): Promise<{
17
+ updated: boolean;
18
+ filePath: string | null;
19
+ alreadyModified: boolean;
20
+ structureType: NextStructure;
21
+ }>;
22
+ export {};
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/onboarding/templates/next/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAIvE,UAAU,uBAAuB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,KAAK,aAAa,GAAG,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC;AAsC5C,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC7B,CAAC,CA4BD"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Pages Directory layout template generator
3
+ * Handles updating Next.js Pages Directory _app.tsx files with ConsentManagerProvider
4
+ */
5
+ import type { AvailablePackages } from '../../../../context/framework-detection';
6
+ interface UpdatePagesLayoutOptions {
7
+ projectRoot: string;
8
+ mode: string;
9
+ backendURL?: string;
10
+ useEnvFile?: boolean;
11
+ pkg: AvailablePackages;
12
+ proxyNextjs?: boolean;
13
+ }
14
+ export declare function updatePagesLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs, }: UpdatePagesLayoutOptions): Promise<{
15
+ updated: boolean;
16
+ filePath: string | null;
17
+ alreadyModified: boolean;
18
+ }>;
19
+ export {};
20
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/onboarding/templates/next/pages/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAOvE,UAAU,wBAAwB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAyJD,wBAAsB,iBAAiB,CAAC,EACvC,WAAW,EACX,IAAI,EACJ,GAAG,EACH,UAAU,EACV,UAAU,EACV,WAAW,GACX,EAAE,wBAAwB,GAAG,OAAO,CAAC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CAgED"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared template configuration generators
3
+ * These functions generate template configuration content for different storage modes
4
+ * Used by both App Directory and Pages Directory implementations
5
+ */
6
+ /**
7
+ * Generates the options text for ConsentManagerProvider based on mode and configuration
8
+ *
9
+ * @param mode - The storage mode ('c15t', 'offline', or 'custom')
10
+ * @param backendURL - URL for the c15t backend/API (for 'c15t' mode)
11
+ * @param useEnvFile - Whether to use environment variable for backendURL
12
+ * @param proxyNextjs - Whether to use Next.js API proxy for c15t mode
13
+ * @returns The formatted options object as a string
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const options = generateOptionsText('c15t', 'https://api.example.com', false, true);
18
+ * // Returns: "{ mode: 'c15t', backendURL: '/api/c15t', ... }"
19
+ * ```
20
+ */
21
+ export declare function generateOptionsText(mode: string, backendURL?: string, useEnvFile?: boolean, proxyNextjs?: boolean): string;
22
+ /**
23
+ * Gets the required base imports for ConsentManagerProvider
24
+ *
25
+ * @returns Array of import names needed for basic consent management
26
+ */
27
+ export declare function getBaseImports(): string[];
28
+ /**
29
+ * Gets additional imports needed for custom mode
30
+ *
31
+ * @returns Array of import configurations for custom handlers
32
+ */
33
+ export declare function getCustomModeImports(): Array<{
34
+ namedImports: string[];
35
+ moduleSpecifier: string;
36
+ }>;
37
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../../src/onboarding/templates/shared/options.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,OAAO,EACpB,WAAW,CAAC,EAAE,OAAO,GACnB,MAAM,CAuCR;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,KAAK,CAAC;IAC7C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACxB,CAAC,CAOD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c15t/cli",
3
- "version": "1.4.4",
3
+ "version": "1.5.0-canary-20250722085128",
4
4
  "description": "The CLI for c15t",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.mjs",
@@ -29,8 +29,8 @@
29
29
  "posthog-node": "^4.11.7",
30
30
  "ts-morph": "^25.0.1",
31
31
  "zod": "^3.24.2",
32
- "@c15t/backend": "1.4.2",
33
- "@c15t/react": "1.4.4"
32
+ "@c15t/backend": "1.5.0-canary-20250722085128",
33
+ "@c15t/react": "1.5.0-canary-20250722085128"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/figlet": "^1.7.0",