@carlonicora/nextjs-jsonapi 1.3.1 → 1.5.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.
Files changed (107) hide show
  1. package/README.md +208 -127
  2. package/dist/AuthComponent-B_Ps2Vb9.d.ts +78 -0
  3. package/dist/AuthComponent-CxnGgvoh.d.mts +78 -0
  4. package/dist/{BlockNoteEditor-V625C23O.mjs → BlockNoteEditor-AIEEQM6A.mjs} +4 -6
  5. package/dist/{BlockNoteEditor-V625C23O.mjs.map → BlockNoteEditor-AIEEQM6A.mjs.map} +1 -1
  6. package/dist/{BlockNoteEditor-7WYPN34K.js → BlockNoteEditor-G6AK2NWA.js} +8 -10
  7. package/dist/BlockNoteEditor-G6AK2NWA.js.map +1 -0
  8. package/dist/chunk-3UELCPIN.js +46 -0
  9. package/dist/chunk-3UELCPIN.js.map +1 -0
  10. package/dist/{chunk-5QC7A6BL.mjs → chunk-J7YDGYSW.mjs} +2668 -1319
  11. package/dist/chunk-J7YDGYSW.mjs.map +1 -0
  12. package/dist/chunk-SZZYEG3P.mjs +46 -0
  13. package/dist/chunk-SZZYEG3P.mjs.map +1 -0
  14. package/dist/{chunk-K2ANOT66.js → chunk-VET55IZO.js} +1869 -520
  15. package/dist/chunk-VET55IZO.js.map +1 -0
  16. package/dist/client/index.d.mts +2 -2
  17. package/dist/client/index.d.ts +2 -2
  18. package/dist/client/index.js +3 -4
  19. package/dist/client/index.js.map +1 -1
  20. package/dist/client/index.mjs +2 -3
  21. package/dist/components/index.d.mts +6 -69
  22. package/dist/components/index.d.ts +6 -69
  23. package/dist/components/index.js +3 -4
  24. package/dist/components/index.js.map +1 -1
  25. package/dist/components/index.mjs +2 -3
  26. package/dist/{content.interface-C_PGZMuy.d.ts → content.interface-CR2aBeAW.d.ts} +1 -1
  27. package/dist/{content.interface-D_WS6CrB.d.mts → content.interface-FpLfsaRm.d.mts} +1 -1
  28. package/dist/contexts/index.d.mts +3 -3
  29. package/dist/contexts/index.d.ts +3 -3
  30. package/dist/contexts/index.js +3 -4
  31. package/dist/contexts/index.js.map +1 -1
  32. package/dist/contexts/index.mjs +2 -3
  33. package/dist/features/index.d.mts +50 -49
  34. package/dist/features/index.d.ts +50 -49
  35. package/dist/features/index.js +24 -3
  36. package/dist/features/index.js.map +1 -1
  37. package/dist/features/index.mjs +23 -2
  38. package/dist/hooks/index.d.mts +3 -3
  39. package/dist/hooks/index.d.ts +3 -3
  40. package/dist/hooks/index.js +3 -4
  41. package/dist/hooks/index.js.map +1 -1
  42. package/dist/hooks/index.mjs +2 -3
  43. package/dist/index.js +2 -2
  44. package/dist/index.mjs +1 -1
  45. package/dist/{notification.interface-BBgMUdLR.d.mts → notification.interface-B2BrLoDA.d.mts} +1 -1
  46. package/dist/{notification.interface-gyvT-Z2F.d.ts → notification.interface-DlZLnAfg.d.ts} +1 -1
  47. package/dist/roles/index.d.mts +7 -1
  48. package/dist/roles/index.d.ts +7 -1
  49. package/dist/roles/index.js +8 -2
  50. package/dist/roles/index.js.map +1 -1
  51. package/dist/roles/index.mjs +7 -1
  52. package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
  53. package/dist/scripts/generate-web-module/generator.js +8 -5
  54. package/dist/scripts/generate-web-module/generator.js.map +1 -1
  55. package/dist/scripts/generate-web-module/index.js +1 -1
  56. package/dist/scripts/generate-web-module/index.js.map +1 -1
  57. package/dist/scripts/generate-web-module/templates/components/editor.template.js +8 -1
  58. package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -1
  59. package/dist/scripts/generate-web-module/transformers/parent-detector.d.ts +4 -3
  60. package/dist/scripts/generate-web-module/transformers/parent-detector.d.ts.map +1 -1
  61. package/dist/scripts/generate-web-module/transformers/parent-detector.js +9 -3
  62. package/dist/scripts/generate-web-module/transformers/parent-detector.js.map +1 -1
  63. package/dist/scripts/generate-web-module/transformers/relationship-resolver.d.ts +11 -0
  64. package/dist/scripts/generate-web-module/transformers/relationship-resolver.d.ts.map +1 -1
  65. package/dist/scripts/generate-web-module/transformers/relationship-resolver.js +36 -9
  66. package/dist/scripts/generate-web-module/transformers/relationship-resolver.js.map +1 -1
  67. package/dist/scripts/generate-web-module/types/json-schema.interface.d.ts +2 -0
  68. package/dist/scripts/generate-web-module/types/json-schema.interface.d.ts.map +1 -1
  69. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +1 -0
  70. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -1
  71. package/dist/scripts/generate-web-module/utils/i18n-updater.d.ts +4 -3
  72. package/dist/scripts/generate-web-module/utils/i18n-updater.d.ts.map +1 -1
  73. package/dist/scripts/generate-web-module/utils/i18n-updater.js +9 -9
  74. package/dist/scripts/generate-web-module/utils/i18n-updater.js.map +1 -1
  75. package/dist/scripts/generate-web-module/validators/json-schema-validator.js +3 -3
  76. package/dist/scripts/generate-web-module/validators/json-schema-validator.js.map +1 -1
  77. package/dist/{useSocket-DzMKRKCA.d.ts → useSocket-BV6yMdWS.d.ts} +1 -1
  78. package/dist/{useSocket-Cn7fB_B1.d.mts → useSocket-L-An7_Mr.d.mts} +1 -1
  79. package/dist/{user.interface-CAsTIbuQ.d.mts → user.interface-CooB1R79.d.mts} +13 -13
  80. package/dist/{user.interface-CbWqMaaU.d.ts → user.interface-KnIT9pVY.d.ts} +13 -13
  81. package/package.json +1 -1
  82. package/scripts/generate-web-module/generator.ts +8 -5
  83. package/scripts/generate-web-module/index.ts +1 -1
  84. package/scripts/generate-web-module/templates/components/editor.template.ts +7 -2
  85. package/scripts/generate-web-module/transformers/parent-detector.ts +10 -3
  86. package/scripts/generate-web-module/transformers/relationship-resolver.ts +36 -9
  87. package/scripts/generate-web-module/types/json-schema.interface.ts +2 -0
  88. package/scripts/generate-web-module/types/template-data.interface.ts +1 -0
  89. package/scripts/generate-web-module/utils/i18n-updater.ts +9 -9
  90. package/scripts/generate-web-module/validators/json-schema-validator.ts +3 -3
  91. package/src/features/auth/components/details/LandingComponent.tsx +27 -29
  92. package/src/features/user/index.ts +1 -0
  93. package/src/roles/config.ts +15 -0
  94. package/src/roles/index.ts +9 -1
  95. package/dist/AuthComponent-hxOPs9o8.d.mts +0 -11
  96. package/dist/AuthComponent-hxOPs9o8.d.ts +0 -11
  97. package/dist/BlockNoteEditor-7WYPN34K.js.map +0 -1
  98. package/dist/chunk-4HCRAOS5.js +0 -28
  99. package/dist/chunk-4HCRAOS5.js.map +0 -1
  100. package/dist/chunk-5QC7A6BL.mjs.map +0 -1
  101. package/dist/chunk-BLWVZK6J.mjs +0 -28
  102. package/dist/chunk-BLWVZK6J.mjs.map +0 -1
  103. package/dist/chunk-HTLEKZND.mjs +0 -1375
  104. package/dist/chunk-HTLEKZND.mjs.map +0 -1
  105. package/dist/chunk-K2ANOT66.js.map +0 -1
  106. package/dist/chunk-PO5Q3H5I.js +0 -1375
  107. package/dist/chunk-PO5Q3H5I.js.map +0 -1
@@ -8,7 +8,7 @@ import { FrontendTemplateData, FrontendField, FrontendRelationship } from "../..
8
8
  import { toCamelCase, pluralize, toPascalCase } from "../../transformers/name-transformer";
9
9
  import { AUTHOR_VARIANT } from "../../types/field-mapping.types";
10
10
  import { getFormFieldJsx } from "../../transformers/field-mapper";
11
- import { getRelationshipFormJsx, getDefaultValueExpression, getPayloadMapping } from "../../transformers/relationship-resolver";
11
+ import { getRelationshipFormJsx, getDefaultValueExpression, getPayloadMapping, isFoundationImport, FOUNDATION_PACKAGE } from "../../transformers/relationship-resolver";
12
12
 
13
13
  /**
14
14
  * Generate the editor component file content
@@ -154,7 +154,12 @@ function generateImports(data: FrontendTemplateData): string {
154
154
  imports.push(`import { UserInterface } from "@/features/foundations/user/data/UserInterface";`);
155
155
  } else {
156
156
  const componentName = rel.single ? `${rel.name}Selector` : `${rel.name}MultiSelector`;
157
- imports.push(`import ${componentName} from "${rel.importPath}";`);
157
+ if (rel.isFoundation) {
158
+ // Foundation entities use named imports from the package
159
+ imports.push(`import { ${componentName} } from "${FOUNDATION_PACKAGE}";`);
160
+ } else {
161
+ imports.push(`import ${componentName} from "${rel.importPath}";`);
162
+ }
158
163
  }
159
164
  });
160
165
 
@@ -2,19 +2,26 @@
2
2
  * Parent Class Detector
3
3
  *
4
4
  * Determines whether a module should extend Content or AbstractApiData
5
- * based on the presence of Content-specific fields.
5
+ * based on the presence of Content-specific fields or explicit configuration.
6
6
  */
7
7
 
8
8
  import { JsonFieldDefinition } from "../types/json-schema.interface";
9
9
  import { CONTENT_INDICATOR_FIELDS } from "../types/field-mapping.types";
10
10
 
11
11
  /**
12
- * Check if a module should extend Content based on its fields
12
+ * Check if a module should extend Content
13
13
  *
14
14
  * @param fields - Array of field definitions from JSON schema
15
+ * @param explicitValue - Optional explicit value from JSON schema
15
16
  * @returns true if the module should extend Content
16
17
  */
17
- export function detectExtendsContent(fields: JsonFieldDefinition[]): boolean {
18
+ export function detectExtendsContent(fields: JsonFieldDefinition[], explicitValue?: boolean): boolean {
19
+ // If explicitly set in JSON schema, use that value
20
+ if (explicitValue !== undefined) {
21
+ return explicitValue;
22
+ }
23
+
24
+ // Otherwise, auto-detect based on fields
18
25
  const fieldNames = fields.map((f) => f.name);
19
26
  return CONTENT_INDICATOR_FIELDS.some((indicator) => fieldNames.includes(indicator));
20
27
  }
@@ -10,6 +10,21 @@ import { FrontendRelationship, RelationshipServiceMethod } from "../types/templa
10
10
  import { AUTHOR_VARIANT, AUTHOR_ZOD_SCHEMA, ENTITY_ZOD_SCHEMA } from "../types/field-mapping.types";
11
11
  import { toCamelCase, toKebabCase, pluralize, toPascalCase } from "./name-transformer";
12
12
 
13
+ /**
14
+ * Foundation package name constant for web imports
15
+ */
16
+ export const FOUNDATION_PACKAGE = "@carlonicora/nextjs-jsonapi/features";
17
+
18
+ /**
19
+ * Check if a directory represents a foundation import (from the package)
20
+ *
21
+ * @param directory - The directory string from relationship definition
22
+ * @returns True if this should import from the foundation package
23
+ */
24
+ export function isFoundationImport(directory: string): boolean {
25
+ return directory === "@foundation" || directory.startsWith("@foundation/");
26
+ }
27
+
13
28
  /**
14
29
  * Resolve a JSON relationship to frontend representation
15
30
  *
@@ -56,11 +71,23 @@ export function resolveRelationship(rel: JsonRelationshipDefinition): FrontendRe
56
71
  zodSchema = rel.nullable ? `z.array(${ENTITY_ZOD_SCHEMA}).optional()` : `z.array(${ENTITY_ZOD_SCHEMA})`;
57
72
  }
58
73
 
59
- // Import paths - map directory to web path
60
- const webDirectory = mapDirectoryToWebPath(rel.directory);
61
- const importPath = `@/features/${webDirectory}/${modelKebab}/components/forms/${selectorComponent}`;
62
- const interfaceImportPath = `@/features/${webDirectory}/${modelKebab}/data/${rel.name}Interface`;
63
- const serviceImportPath = `@/features/${webDirectory}/${modelKebab}/data/${rel.name}Service`;
74
+ // Import paths - check for foundation imports
75
+ let importPath: string;
76
+ let interfaceImportPath: string;
77
+ let serviceImportPath: string;
78
+
79
+ if (isFoundationImport(rel.directory)) {
80
+ // Foundation entities import from the package
81
+ importPath = FOUNDATION_PACKAGE;
82
+ interfaceImportPath = FOUNDATION_PACKAGE;
83
+ serviceImportPath = FOUNDATION_PACKAGE;
84
+ } else {
85
+ // Feature entities use local paths
86
+ const webDirectory = mapDirectoryToWebPath(rel.directory);
87
+ importPath = `@/features/${webDirectory}/${modelKebab}/components/forms/${selectorComponent}`;
88
+ interfaceImportPath = `@/features/${webDirectory}/${modelKebab}/data/${rel.name}Interface`;
89
+ serviceImportPath = `@/features/${webDirectory}/${modelKebab}/data/${rel.name}Service`;
90
+ }
64
91
 
65
92
  return {
66
93
  name: rel.name,
@@ -68,6 +95,7 @@ export function resolveRelationship(rel: JsonRelationshipDefinition): FrontendRe
68
95
  directory: rel.directory,
69
96
  single: rel.single,
70
97
  nullable: rel.nullable,
98
+ isFoundation: isFoundationImport(rel.directory),
71
99
  formFieldId,
72
100
  formFieldIdPlural,
73
101
  payloadFieldId,
@@ -131,10 +159,9 @@ export function getSelectorImports(relationships: FrontendRelationship[]): strin
131
159
  const imports = new Set<string>();
132
160
 
133
161
  relationships.forEach((rel) => {
134
- // Don't import User selector from same module - it's typically a library import
135
- if (rel.name === "User" && rel.variant === AUTHOR_VARIANT) {
136
- // User selector is imported from library or user feature
137
- imports.add(`import { UserSelector } from "@/features/foundations/user/components/forms/UserSelector";`);
162
+ if (isFoundationImport(rel.directory)) {
163
+ // Foundation entities use named imports from the package
164
+ imports.add(`import { ${rel.selectorComponent} } from "${FOUNDATION_PACKAGE}";`);
138
165
  } else {
139
166
  imports.add(`import ${rel.selectorComponent} from "${rel.importPath}";`);
140
167
  }
@@ -39,4 +39,6 @@ export interface JsonModuleDefinition {
39
39
  languages: string[];
40
40
  fields: JsonFieldDefinition[];
41
41
  relationships: JsonRelationshipDefinition[];
42
+ /** Explicitly set whether this module extends Content. If not set, auto-detects based on fields. */
43
+ extendsContent?: boolean;
42
44
  }
@@ -46,6 +46,7 @@ export interface FrontendRelationship {
46
46
  directory: string; // e.g., "foundations"
47
47
  single: boolean;
48
48
  nullable: boolean;
49
+ isFoundation: boolean; // true if importing from @carlonicora/nextjs-jsonapi/features
49
50
  // Derived properties
50
51
  formFieldId: string; // e.g., "author" (lowercase variant) or "user"
51
52
  formFieldIdPlural: string; // e.g., "topics" for multi-select
@@ -1,15 +1,13 @@
1
1
  /**
2
2
  * i18n Updater
3
3
  *
4
- * Updates the messages/en.json file with new module translations.
4
+ * Updates the messages/{language}.json files with new module translations.
5
5
  */
6
6
 
7
7
  import * as fs from "fs";
8
8
  import { FrontendTemplateData } from "../types/template-data.interface";
9
9
  import { buildI18nMessages } from "../transformers/i18n-generator";
10
10
 
11
- const MESSAGES_PATH = "apps/web/messages/en.json";
12
-
13
11
  export interface I18nUpdateResult {
14
12
  success: boolean;
15
13
  message: string;
@@ -17,20 +15,22 @@ export interface I18nUpdateResult {
17
15
  }
18
16
 
19
17
  /**
20
- * Update messages/en.json with new module translations
18
+ * Update messages/{language}.json with new module translations
21
19
  *
22
20
  * @param data - Frontend template data
23
21
  * @param webBasePath - Base path to web app
22
+ * @param language - Language code (e.g., "en", "es", "fr")
24
23
  * @param dryRun - Whether to perform a dry run
25
24
  * @returns Update result
26
25
  */
27
26
  export function updateI18n(
28
27
  data: FrontendTemplateData,
29
28
  webBasePath: string,
29
+ language: string = "en",
30
30
  dryRun: boolean = false
31
31
  ): I18nUpdateResult {
32
32
  const { names, i18nKeys } = data;
33
- const messagesPath = `${webBasePath}/${MESSAGES_PATH}`;
33
+ const messagesPath = `${webBasePath}/apps/web/messages/${language}.json`;
34
34
 
35
35
  // Check if file exists
36
36
  if (!fs.existsSync(messagesPath)) {
@@ -48,7 +48,7 @@ export function updateI18n(
48
48
  } catch (e) {
49
49
  return {
50
50
  success: false,
51
- message: `Failed to parse messages/en.json: ${e}`,
51
+ message: `Failed to parse messages/${language}.json: ${e}`,
52
52
  };
53
53
  }
54
54
 
@@ -56,7 +56,7 @@ export function updateI18n(
56
56
  if (messages.features && messages.features[names.camelCase]) {
57
57
  return {
58
58
  success: true,
59
- message: `Module ${names.camelCase} already exists in messages/en.json`,
59
+ message: `Module ${names.camelCase} already exists in messages/${language}.json`,
60
60
  alreadyExists: true,
61
61
  };
62
62
  }
@@ -82,7 +82,7 @@ export function updateI18n(
82
82
  if (dryRun) {
83
83
  return {
84
84
  success: true,
85
- message: `[DRY RUN] Would update messages/en.json with ${names.camelCase} translations`,
85
+ message: `[DRY RUN] Would update messages/${language}.json with ${names.camelCase} translations`,
86
86
  };
87
87
  }
88
88
 
@@ -92,7 +92,7 @@ export function updateI18n(
92
92
 
93
93
  return {
94
94
  success: true,
95
- message: `Updated messages/en.json with ${names.camelCase} translations`,
95
+ message: `Updated messages/${language}.json with ${names.camelCase} translations`,
96
96
  };
97
97
  }
98
98
 
@@ -134,11 +134,11 @@ export function validateJsonSchema(schema: any): ValidationError[] {
134
134
  });
135
135
  }
136
136
 
137
- // Directory should be features or foundations
138
- if (rel.directory && !["features", "foundations"].includes(rel.directory)) {
137
+ // Directory should be features, foundations, or @foundation (for package imports)
138
+ if (rel.directory && !["features", "foundations", "@foundation"].includes(rel.directory) && !rel.directory.startsWith("@foundation/")) {
139
139
  errors.push({
140
140
  field: `relationships[${index}].directory`,
141
- message: 'Relationship directory should be "features" or "foundations"',
141
+ message: 'Relationship directory should be "features", "foundations", or "@foundation"',
142
142
  severity: "warning",
143
143
  });
144
144
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useTranslations } from "next-intl";
4
4
  import Image from "next/image";
5
+ import { isDiscordConfigured, isInternalAuthConfigured } from "../../../../roles";
5
6
  import { Button, CardDescription, CardFooter, CardHeader, CardTitle, Link } from "../../../../shadcnui";
6
7
  import { getApiUrl } from "../../../../unified";
7
8
  import { useAuthContext } from "../../contexts";
@@ -23,35 +24,32 @@ export function LandingComponent() {
23
24
  {t(`generic.description`)}
24
25
  </CardDescription>
25
26
  </CardHeader>
26
- <CardFooter className="mt-4 flex w-full flex-col justify-between">
27
- <Link href="#" className="flex w-full justify-start" onClick={() => setComponentType(AuthComponent.Register)}>
28
- <Button className="mt-4 w-full" variant={`default`}>
29
- {t(`foundations.auth.buttons.register`)}
30
- </Button>
31
- </Link>
32
- <Link href="#" className="flex w-full justify-end" onClick={() => setComponentType(AuthComponent.Login)}>
33
- <Button className="mt-4 w-full" variant={`outline`} data-testid="page-login-button-initial-login">
34
- {t(`foundations.auth.buttons.login`)}
35
- </Button>
36
- </Link>
37
-
38
- <Button
39
- onClick={(e) => {
40
- e.preventDefault();
41
- window.location.href = `${getApiUrl()}auth/discord`;
42
- }}
43
- className={`flex w-full justify-end`}
44
- >
45
- {/* <Image
46
- className="flex h-4 w-5 items-center justify-center"
47
- src={discordIcon}
48
- alt="discordIcon"
49
- width={20}
50
- height={16}
51
- style={{ width: "20px", height: "16px" }}
52
- /> */}
53
- <div className="text-sm font-medium leading-normal">Discord</div>
54
- </Button>
27
+ <CardFooter className="mt-4 flex w-full flex-col justify-between gap-y-4">
28
+ {isInternalAuthConfigured() && (
29
+ <>
30
+ <Link
31
+ href="#"
32
+ className="flex w-full justify-start"
33
+ onClick={() => setComponentType(AuthComponent.Register)}
34
+ >
35
+ <Button className="w-full" variant={`default`}>
36
+ {t(`foundations.auth.buttons.register`)}
37
+ </Button>
38
+ </Link>
39
+ <Link href="#" className="flex w-full justify-end" onClick={() => setComponentType(AuthComponent.Login)}>
40
+ <Button className="w-full" variant={`outline`} data-testid="page-login-button-initial-login">
41
+ {t(`foundations.auth.buttons.login`)}
42
+ </Button>
43
+ </Link>
44
+ </>
45
+ )}
46
+ {isDiscordConfigured() && (
47
+ <Link href={`${getApiUrl()}auth/discord`} className="flex w-full justify-end">
48
+ <Button className="w-full" variant={`outline`} data-testid="page-login-button-initial-login">
49
+ Login with Discord
50
+ </Button>
51
+ </Link>
52
+ )}
55
53
  </CardFooter>
56
54
  </>
57
55
  );
@@ -1,3 +1,4 @@
1
1
  export * from "./author.module";
2
+ export * from "./components/forms";
2
3
  export * from "./data";
3
4
  export * from "./user.module";
@@ -10,6 +10,8 @@ export interface RoleIdConfig {
10
10
 
11
11
  // Private storage for the injected role IDs
12
12
  let _roleId: RoleIdConfig | null = null;
13
+ let _useDiscord: boolean = false;
14
+ let _useInternalAuth: boolean = true;
13
15
 
14
16
  /**
15
17
  * Configure role IDs for the library
@@ -27,6 +29,11 @@ export function configureRoles(roleId: RoleIdConfig): void {
27
29
  _roleId = roleId;
28
30
  }
29
31
 
32
+ export function configureDiscord(params: { useDiscord: boolean; useInternalAuth: boolean }): void {
33
+ _useDiscord = params.useDiscord;
34
+ _useInternalAuth = params.useInternalAuth;
35
+ }
36
+
30
37
  /**
31
38
  * Get configured role IDs
32
39
  * @throws Error if roles not configured
@@ -44,3 +51,11 @@ export function getRoleId(): RoleIdConfig {
44
51
  export function isRolesConfigured(): boolean {
45
52
  return _roleId !== null;
46
53
  }
54
+
55
+ export function isDiscordConfigured(): boolean {
56
+ return _useDiscord;
57
+ }
58
+
59
+ export function isInternalAuthConfigured(): boolean {
60
+ return _useInternalAuth;
61
+ }
@@ -1 +1,9 @@
1
- export { configureRoles, getRoleId, isRolesConfigured, type RoleIdConfig } from "./config";
1
+ export {
2
+ configureDiscord,
3
+ configureRoles,
4
+ getRoleId,
5
+ isDiscordConfigured,
6
+ isInternalAuthConfigured,
7
+ isRolesConfigured,
8
+ type RoleIdConfig,
9
+ } from "./config";
@@ -1,11 +0,0 @@
1
- declare enum AuthComponent {
2
- Login = 0,
3
- ForgotPassword = 1,
4
- ResetPassword = 2,
5
- ActivateAccount = 3,
6
- AcceptInvitation = 4,
7
- Register = 5,
8
- Landing = 6
9
- }
10
-
11
- export { AuthComponent as A };
@@ -1,11 +0,0 @@
1
- declare enum AuthComponent {
2
- Login = 0,
3
- ForgotPassword = 1,
4
- ResetPassword = 2,
5
- ActivateAccount = 3,
6
- AcceptInvitation = 4,
7
- Register = 5,
8
- Landing = 6
9
- }
10
-
11
- export { AuthComponent as A };
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/BlockNoteEditor-7WYPN34K.js","../src/components/editors/BlockNoteEditor.tsx","../src/components/editors/BlockNoteEditorFormattingToolbar.tsx"],"names":["jsxs","jsx"],"mappings":"AAAA,ylBAAY;AACZ;AACE;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACA;AC3BA,uCAAyE;AACzE,yCAAiE;AACjE,2CAA8B;AAC9B,uCAAO;AACP,2CAAiC;AACjC,qCAAgC;AAChC,+BAAyE;AD6BzE;AACA;AEpCA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAOM,+CAAA;AAJD,SAAS,gCAAA,CAAA,EAAmC;AACjD,EAAA,uBACE,6BAAA;AAAA,IAAC,kCAAA;AAAA,IAAA;AAAA,MACC,iBAAA,EAAmB,CAAA,EAAA,mBACjB,8BAAA,wBAAC,EAAA,EACC,QAAA,EAAA;AAAA,wBAAA,6BAAA,sBAAC,EAAA,CAAA,CAAA,EAAqB,iBAAmB,CAAA;AAAA,wBAEzC,6BAAA,wBAAC,EAAA,CAAA,CAAA,EAAuB,mBAAqB,CAAA;AAAA,wBAC7C,6BAAA,wBAAC,EAAA,CAAA,CAAA,EAAuB,mBAAqB,CAAA;AAAA,wBAE7C,6BAAA,2BAAC,EAAA,EAAqB,cAAA,EAAgB,OAAA,CAAA,EAAa,iBAAmB,CAAA;AAAA,wBACtE,6BAAA,2BAAC,EAAA,EAAqB,cAAA,EAAgB,SAAA,CAAA,EAAe,mBAAqB,CAAA;AAAA,wBAC1E,6BAAA,2BAAC,EAAA,EAAqB,cAAA,EAAgB,YAAA,CAAA,EAAkB,sBAAwB,CAAA;AAAA,wBAChF,6BAAA,2BAAC,EAAA,EAAqB,cAAA,EAAgB,SAAA,CAAA,EAAe,mBAAqB,CAAA;AAAA,wBAE1E,6BAAA,sBAAC,EAAA,EAAgB,aAAA,EAAe,OAAA,CAAA,EAAa,qBAAuB,CAAA;AAAA,wBACpE,6BAAA,sBAAC,EAAA,EAAgB,aAAA,EAAe,SAAA,CAAA,EAAe,uBAAyB,CAAA;AAAA,wBACxE,6BAAA,sBAAC,EAAA,EAAgB,aAAA,EAAe,QAAA,CAAA,EAAc,sBAAwB,CAAA;AAAA,wBAEtE,6BAAA,uBAAC,EAAA,CAAA,CAAA,EAAsB,kBAAoB;AAAA,MAAA,EAAA,CAC7C;AAAA,IAAA;AAAA,EAEJ,CAAA;AAEJ;AAxBgB,qCAAA,gCAAA,EAAA,kCAAA,CAAA;AF0DhB;AACA;ACxBU;AAnBV,IAAM,mCAAA,kBAAqC,qCAAA,CACzC,kBAAA,EACA,kBAAA,EAAA,GACG;AACH,EAAA,OAAO,iDAAA;AAAA,IACL;AAAA,MACE,IAAA,EAAM,aAAA;AAAA,MACN,UAAA,EAAY;AAAA,QACV,OAAA,EAAS;AAAA,UACP,OAAA,EAAS;AAAA,QACX;AAAA,MACF,CAAA;AAAA,MACA,OAAA,EAAS;AAAA,IACX,CAAA;AAAA,IACA;AAAA,MACE,MAAA,kBAAQ,qCAAA,CAAC,KAAA,EAAA,GAAU;AACjB,QAAA,MAAM,QAAA,EAAU,KAAA,CAAM,aAAA,CAAc,KAAA,CAAM,OAAA;AAE1C,QAAA,uBACEA,8BAAAA,MAAC,EAAA,EAAK,SAAA,EAAU,yEAAA,EACd,QAAA,EAAA;AAAA,0BAAAC,6BAAAA;AAAA,YAAC,uBAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,eAAA;AAAA,cACN,OAAA,EAAS,CAAC,CAAA,EAAA,GAAM;AACd,gBAAA,CAAA,CAAE,cAAA,CAAe,CAAA;AACjB,gBAAA,CAAA,CAAE,eAAA,CAAgB,CAAA;AAClB,gBAAA,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAA,EAAA,GAAe,kBAAA,CAAmB,EAAA,CAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,cAC1E,CAAA;AAAA,cAEA,QAAA,kBAAAA,6BAAAA,sBAAC,EAAA,EAAU,SAAA,EAAU,yBAAA,CAAyB;AAAA,YAAA;AAAA,UAChD,CAAA;AAAA,0BACAA,6BAAAA;AAAA,YAAC,uBAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,eAAA;AAAA,cACN,SAAA,EAAU,UAAA;AAAA,cACV,OAAA,EAAS,CAAC,CAAA,EAAA,GAAM;AACd,gBAAA,CAAA,CAAE,cAAA,CAAe,CAAA;AACjB,gBAAA,CAAA,CAAE,eAAA,CAAgB,CAAA;AAClB,gBAAA,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,CAAC,EAAA,EAAA,GAAe,kBAAA,CAAmB,EAAA,CAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,cAC1E,CAAA;AAAA,cAEA,QAAA,kBAAAA,6BAAAA,kBAAC,EAAA,EAAM,SAAA,EAAU,uBAAA,CAAuB;AAAA,YAAA;AAAA,UAC1C;AAAA,QAAA,EAAA,CACF,CAAA;AAAA,MAEJ,CAAA,EA5BQ,QAAA;AAAA,IA6BV;AAAA,EACF,CAAA;AACF,CAAA,EA9C2C,oCAAA,CAAA;AAgD5B,SAAR,eAAA,CAAiC;AAAA,EACtC,EAAA;AAAA,EACA,IAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA,eAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAC1C,EAAA,MAAM,EAAA,EAAI,uCAAA,CAAgB;AAC1B,EAAA,MAAM,EAAE,QAAQ,EAAA,EAAI,oDAAA,CAAqC;AAEzD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,EAAA,EAAI,8BAAA,gBAAsB,IAAI,GAAA,CAAI,CAAC,CAAA;AAC7E,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,EAAA,EAAI,8BAAA,gBAAsB,IAAI,GAAA,CAAI,CAAC,CAAA;AAE7E,EAAA,MAAM,UAAA,EAAY,4BAAA,IAA2B,CAAA;AAE7C,EAAA,MAAM,mBAAA,EAAqB,iCAAA,CAAa,MAAA,EAAA,GAAmB;AACzD,IAAA,kBAAA,CAAmB,CAAC,IAAA,EAAA,mBAAS,IAAI,GAAA,CAAI,CAAC,GAAG,IAAA,EAAM,MAAM,CAAC,CAAC,CAAA;AACvD,IAAA,kBAAA,CAAmB,CAAC,IAAA,EAAA,GAAS;AAC3B,MAAA,MAAM,OAAA,EAAS,IAAI,GAAA,CAAI,IAAI,CAAA;AAC3B,MAAA,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AACpB,MAAA,OAAO,MAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,MAAM,mBAAA,EAAqB,iCAAA,CAAa,MAAA,EAAA,GAAmB;AACzD,IAAA,kBAAA,CAAmB,CAAC,IAAA,EAAA,mBAAS,IAAI,GAAA,CAAI,CAAC,GAAG,IAAA,EAAM,MAAM,CAAC,CAAC,CAAA;AACvD,IAAA,kBAAA,CAAmB,CAAC,IAAA,EAAA,GAAS;AAC3B,MAAA,MAAM,OAAA,EAAS,IAAI,GAAA,CAAI,IAAI,CAAA;AAC3B,MAAA,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AACpB,MAAA,OAAO,MAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,MAAM,yBAAA,EAA2B,6BAAA;AAAA,IAC/B,CAAA,EAAA,GAAM,kCAAA,CAAmC,kBAAA,EAAoB,kBAAkB,CAAA;AAAA,IAC/E,CAAC,kBAAA,EAAoB,kBAAkB;AAAA,EACzC,CAAA;AAEA,EAAA,MAAM,OAAA,EAAS,6BAAA;AAAA,IACb,CAAA,EAAA,GACE,qBAAA,CAAgB,MAAA,CAAO;AAAA,MACrB,kBAAA,EAAoB;AAAA,QAClB,GAAG,+BAAA;AAAA,QACH,WAAA,EAAa;AAAA,MACf;AAAA,IACF,CAAQ,CAAA;AAAA,IACV,CAAC,wBAAwB;AAAA,EAC3B,CAAA;AAEA,EAAA,MAAM,YAAA,EAAc,iCAAA;AAAA,IAClB,MAAA,CAAO,IAAA,EAAA,GAAgC;AACrC,MAAA,GAAA,CAAI,CAAC,OAAA,EAAS;AACZ,QAAA,yCAAA;AAAW,UACT,KAAA,EAAO,CAAA,CAAE,CAAA,qBAAA,CAAuB,CAAA;AAAA,UAChC,KAAA,EAAO,CAAA,CAAE,CAAA,iCAAA,CAAmC;AAAA,QAC9C,CAAC,CAAA;AACD,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,CAAE,CAAA,qBAAA,CAAuB,CAAC,CAAA;AAAA,MAC5C;AAEA,MAAA,MAAM,SAAA,EAAW,IAAA,CAAK,IAAA;AACtB,MAAA,MAAM,IAAA,EAAM,CAAA,UAAA,EAAa,OAAA,CAAQ,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA;AAEN,MAAA;AACtD,QAAA;AACa,QAAA;AACH,QAAA;AACX,MAAA;AAEmB,MAAA;AACV,QAAA;AACI,QAAA;AACN,QAAA;AACP,MAAA;AAE6D,MAAA;AAC5D,QAAA;AACU,QAAA;AACX,MAAA;AAEkB,MAAA;AACrB,IAAA;AACe,IAAA;AACjB,EAAA;AAGkC,EAAA;AACY,IAAA;AACC,MAAA;AAGR,MAAA;AAEV,MAAA;AAGC,MAAA;AACkB,QAAA;AAKtC,QAAA;AAIkB,QAAA;AACT,UAAA;AACN,QAAA;AACL,UAAA;AACF,QAAA;AACF,MAAA;AAEO,MAAA;AACT,IAAA;AACS,IAAA;AACX,EAAA;AAEuC,EAAA;AACF,IAAA;AAC7B,MAAA;AACwD,QAAA;AACP,QAAA;AACtC,UAAA;AACX,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AAC6C,QAAA;AAC/B,MAAA;AAC4C,QAAA;AAG5D,MAAA;AACF,IAAA;AAEqB,IAAA;AACX,MAAA;AACV,IAAA;AAEoC,IAAA;AAC1B,MAAA;AACV,IAAA;AAE6D,IAAA;AAC5D,EAAA;AACD,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AAE6C,EAAA;AACe,IAAA;AACG,MAAA;AACV,QAAA;AACf,QAAA;AAC1B,QAAA;AACR,MAAA;AAC2E,MAAA;AAC9E,IAAA;AACO,IAAA;AACY,EAAA;AAEN,EAAA;AACb,IAAA;AACS,MAAA;AACS,QAAA;AACoB,UAAA;AAClC,QAAA;AACA,QAAA;AACgB,QAAA;AACJ,QAAA;AACd,MAAA;AAC6D,MAAA;AAC/D,IAAA;AACF,EAAA;AAE6C,EAAA;AAC5B,IAAA;AACU,IAAA;AAEsC,IAAA;AAEL,IAAA;AACR,MAAA;AACnC,MAAA;AAC+C,MAAA;AACD,MAAA;AACI,MAAA;AACtD,QAAA;AACT,MAAA;AAEmB,MAAA;AACuC,QAAA;AACvB,QAAA;AACW,UAAA;AACa,YAAA;AAEN,cAAA;AACvB,cAAA;AACuB,gBAAA;AACM,gBAAA;AACxC,kBAAA;AACT,gBAAA;AACF,cAAA;AACF,YAAA;AACyC,YAAA;AACL,cAAA;AACmB,cAAA;AAC5C,gBAAA;AACT,cAAA;AACF,YAAA;AACuD,YAAA;AAChB,cAAA;AACY,gBAAA;AACjD,cAAA;AACF,YAAA;AACF,UAAA;AACF,QAAA;AACF,MAAA;AACmC,MAAA;AACG,QAAA;AACa,UAAA;AACjD,QAAA;AACF,MAAA;AACO,MAAA;AACT,IAAA;AA3CS,IAAA;AA6Ce,IAAA;AACM,IAAA;AACuB,MAAA;AACrD,IAAA;AAEiE,IAAA;AACR,EAAA;AAGH,EAAA;AACT,IAAA;AADxB,EAAA;AAKsC,EAAA;AAC7C,EAAA;AACoC,IAAA;AACa,MAAA;AACf,MAAA;AACA,QAAA;AAC9C,MAAA;AAJoB,IAAA;AAOwC,IAAA;AACvB,MAAA;AACmB,MAAA;AAC1D,IAAA;AAC0B,EAAA;AAI6B,EAAA;AACzC,EAAA;AACoB,IAAA;AACU,IAAA;AACC,IAAA;AACK,IAAA;AACxB,IAAA;AACS,MAAA;AACjC,MAAA;AACF,IAAA;AACwE,IAAA;AACvC,IAAA;AACN,EAAA;AAGD,EAAA;AACL,IAAA;AACf,MAAA;AAEqD,QAAA;AACP,QAAA;AAC1B,UAAA;AACtB,QAAA;AAGkC,QAAA;AACpB,MAAA;AAC0C,QAAA;AAEpD,QAAA;AACoB,UAAA;AACC,UAAA;AACqB,YAAA;AACM,YAAA;AACd,YAAA;AACpC,UAAA;AACsB,QAAA;AAC2B,UAAA;AACnD,QAAA;AACF,MAAA;AACF,IAAA;AACO,IAAA;AACT,EAAA;AAGqC,EAAA;AAChC,IAAA;AAAA,IAAA;AACC,MAAA;AACU,MAAA;AACa,MAAA;AACJ,MAAA;AACb,MAAA;AACuD,MAAA;AAE5D,MAAA;AAAiC,IAAA;AAEtC,EAAA;AAEJ;AAtUwB;ADuT6C;AACA;AACA","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/BlockNoteEditor-7WYPN34K.js","sourcesContent":[null,"\"use client\";\n\nimport { BlockNoteSchema, defaultInlineContentSpecs, PartialBlock } from \"@blocknote/core\";\nimport { createReactInlineContentSpec, useCreateBlockNote } from \"@blocknote/react\";\nimport { BlockNoteView } from \"@blocknote/shadcn\";\nimport \"@blocknote/shadcn/style.css\";\nimport { CheckIcon, XIcon } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useCurrentUserContext } from \"../../contexts\";\nimport { S3Interface, S3Service, UserInterface } from \"../../features\";\nimport { Button } from \"../../shadcnui\";\nimport { BlockNoteDiffUtil, BlockNoteWordDiffRendererUtil, cn } from \"../../utils\";\nimport { errorToast } from \"../errors\";\nimport { BlockNoteEditorFormattingToolbar } from \"./BlockNoteEditorFormattingToolbar\";\n\nexport type BlockNoteEditorProps = {\n id: string;\n type: string;\n initialContent?: PartialBlock[];\n onChange?: (content: any, isEmpty: boolean, hasUnresolvedDiff: boolean) => void;\n size?: \"sm\" | \"md\";\n className?: string;\n markdownContent?: string;\n diffContent?: PartialBlock[];\n placeholder?: string;\n bordered?: boolean;\n};\n\nconst createDiffActionsInlineContentSpec = (\n handleAcceptChange: (diffId: string) => void,\n handleRejectChange: (diffId: string) => void,\n) => {\n return createReactInlineContentSpec(\n {\n type: \"diffActions\",\n propSchema: {\n diffIds: {\n default: \"\",\n },\n },\n content: \"none\",\n },\n {\n render: (props) => {\n const diffIds = props.inlineContent.props.diffIds;\n\n return (\n <span className=\"diff-actions-container mx-2 inline-flex items-center gap-1 align-middle\">\n <Button\n title=\"Accept change\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n diffIds.split(\",\").forEach((id: string) => handleAcceptChange(id.trim()));\n }}\n >\n <CheckIcon className=\"h-3 w-3 text-green-600\" />\n </Button>\n <Button\n title=\"Reject change\"\n className=\"mx-2 p-0\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n diffIds.split(\",\").forEach((id: string) => handleRejectChange(id.trim()));\n }}\n >\n <XIcon className=\"h-3 w-3 text-red-600\" />\n </Button>\n </span>\n );\n },\n },\n );\n};\n\nexport default function BlockNoteEditor({\n id,\n type,\n initialContent,\n onChange,\n size,\n className,\n markdownContent,\n diffContent,\n placeholder,\n bordered,\n}: BlockNoteEditorProps): React.JSX.Element {\n const t = useTranslations();\n const { company } = useCurrentUserContext<UserInterface>();\n\n const [acceptedChanges, setAcceptedChanges] = useState<Set<string>>(new Set());\n const [rejectedChanges, setRejectedChanges] = useState<Set<string>>(new Set());\n\n const editorRef = useRef<HTMLDivElement>(null);\n\n const handleAcceptChange = useCallback((diffId: string) => {\n setAcceptedChanges((prev) => new Set([...prev, diffId]));\n setRejectedChanges((prev) => {\n const newSet = new Set(prev);\n newSet.delete(diffId);\n return newSet;\n });\n }, []);\n\n const handleRejectChange = useCallback((diffId: string) => {\n setRejectedChanges((prev) => new Set([...prev, diffId]));\n setAcceptedChanges((prev) => {\n const newSet = new Set(prev);\n newSet.delete(diffId);\n return newSet;\n });\n }, []);\n\n const DiffActionsInlineContent = useMemo(\n () => createDiffActionsInlineContentSpec(handleAcceptChange, handleRejectChange),\n [handleAcceptChange, handleRejectChange],\n );\n\n const schema = useMemo(\n () =>\n BlockNoteSchema.create({\n inlineContentSpecs: {\n ...defaultInlineContentSpecs,\n diffActions: DiffActionsInlineContent,\n },\n } as any),\n [DiffActionsInlineContent],\n );\n\n const uploadImage = useCallback(\n async (file: File): Promise<string> => {\n if (!company) {\n errorToast({\n title: t(`generic.errors.upload`),\n error: t(`generic.errors.upload_description`),\n });\n throw new Error(t(`generic.errors.upload`));\n }\n\n const fileType = file.type;\n const key = `companies/${company.id}/${type}/${id}/${file.name}`;\n\n const s3: S3Interface = await S3Service.getPreSignedUrl({\n key: key,\n contentType: fileType,\n isPublic: true,\n });\n\n await fetch(s3.url, {\n method: \"PUT\",\n headers: s3.headers,\n body: file,\n });\n\n const signedImage: S3Interface = await S3Service.getSignedUrl({\n key: key,\n isPublic: true,\n });\n\n return signedImage.url;\n },\n [company, id, t],\n );\n\n // Utility: Remove trailing empty blocks for read-only display\n const removeTrailingEmptyBlocks = useCallback(\n (blocks: PartialBlock[]): PartialBlock[] => {\n if (!blocks || blocks.length === 0) return blocks;\n\n // Only remove trailing empty blocks in read-only mode\n if (onChange !== undefined) return blocks;\n\n const result = [...blocks];\n\n // Remove trailing empty paragraph blocks, but keep at least one block\n while (result.length > 1) {\n const lastBlock = result[result.length - 1];\n\n // Check if it's an empty paragraph\n const isEmptyParagraph =\n lastBlock.type === \"paragraph\" &&\n (!lastBlock.content ||\n lastBlock.content.length === 0 ||\n (Array.isArray(lastBlock.content) && lastBlock.content.every((c: any) => !c.text || c.text.trim() === \"\")));\n\n if (isEmptyParagraph) {\n result.pop();\n } else {\n break;\n }\n }\n\n return result;\n },\n [onChange],\n );\n\n const processedContent = useMemo(() => {\n if (diffContent && initialContent) {\n try {\n const diffResult = BlockNoteDiffUtil.diff(initialContent, diffContent);\n const renderedDiff = BlockNoteWordDiffRendererUtil.renderWordDiffs(\n diffResult.blocks,\n handleAcceptChange,\n handleRejectChange,\n acceptedChanges,\n rejectedChanges,\n );\n return removeTrailingEmptyBlocks(renderedDiff);\n } catch (error) {\n return initialContent && Array.isArray(initialContent) && initialContent.length > 0\n ? removeTrailingEmptyBlocks(initialContent)\n : [];\n }\n }\n\n if (!initialContent) {\n return [];\n }\n\n if (!Array.isArray(initialContent)) {\n return [];\n }\n\n return initialContent.length > 0 ? removeTrailingEmptyBlocks(initialContent) : [];\n }, [\n initialContent,\n diffContent,\n handleAcceptChange,\n handleRejectChange,\n acceptedChanges,\n rejectedChanges,\n removeTrailingEmptyBlocks,\n ]);\n\n const validatedInitialContent = useMemo(() => {\n if (processedContent && Array.isArray(processedContent) && processedContent.length > 0) {\n const validatedContent = processedContent.filter((block) => {\n if (!block || typeof block !== \"object\") return false;\n if (!(block as any).type) return false;\n return true;\n });\n return validatedContent.length > 0 ? (validatedContent as PartialBlock[]) : undefined;\n }\n return undefined;\n }, [processedContent]);\n\n const editor = useCreateBlockNote(\n useMemo(\n () => ({\n placeholders: {\n emptyDocument: placeholder || t(`generic.blocknote.placeholder`),\n },\n schema,\n initialContent: validatedInitialContent,\n uploadFile: uploadImage,\n }),\n [placeholder, t, schema, validatedInitialContent, uploadImage],\n ),\n );\n\n const handleChange = useCallback(async () => {\n if (!onChange) return;\n const newBlocks = editor.document;\n\n const markdownFromBlocks = (await editor.blocksToMarkdownLossy(editor.document)).trim();\n\n function hasUnresolvedDiffsRecursive(block: any): boolean {\n if (!block || typeof block !== \"object\") return false;\n let diffId = undefined;\n if (block.props && block.props.diffId) diffId = block.props.diffId;\n if (!diffId && block.attrs && block.attrs.diffId) diffId = block.attrs.diffId;\n if (diffId && !acceptedChanges.has(diffId) && !rejectedChanges.has(diffId)) {\n return true;\n }\n\n if (block.content) {\n const contentArr = Array.isArray(block.content) ? block.content : [block.content];\n for (const inline of contentArr) {\n if (inline && typeof inline === \"object\") {\n if (inline.type === \"diffActions\" && inline.props && inline.props.diffIds) {\n const ids =\n typeof inline.props.diffIds === \"string\" ? inline.props.diffIds.split(\",\") : inline.props.diffIds;\n for (const id of ids) {\n const trimmed = (id || \"\").toString().trim();\n if (trimmed && !acceptedChanges.has(trimmed) && !rejectedChanges.has(trimmed)) {\n return true;\n }\n }\n }\n if (inline.props && inline.props.diffId) {\n const diffIdInline = inline.props.diffId;\n if (diffIdInline && !acceptedChanges.has(diffIdInline) && !rejectedChanges.has(diffIdInline)) {\n return true;\n }\n }\n if (inline.children && Array.isArray(inline.children)) {\n for (const child of inline.children) {\n if (hasUnresolvedDiffsRecursive(child)) return true;\n }\n }\n }\n }\n }\n if (Array.isArray(block.children)) {\n for (const child of block.children) {\n if (hasUnresolvedDiffsRecursive(child)) return true;\n }\n }\n return false;\n }\n\n let hasUnresolvedDiff = false;\n if (Array.isArray(newBlocks)) {\n hasUnresolvedDiff = newBlocks.some((block: any) => hasUnresolvedDiffsRecursive(block));\n }\n\n onChange(newBlocks, !markdownFromBlocks.length, hasUnresolvedDiff);\n }, [editor, onChange, id, acceptedChanges, rejectedChanges]);\n\n // Utility: deep equality for arrays of blocks\n const areBlocksEqual = (a: any[], b: any[]): boolean => {\n return JSON.stringify(a) === JSON.stringify(b);\n };\n\n // Only initialize from markdownContent once per value, and only if different\n const hasInitializedFromMarkdown = useRef<string | null>(null);\n useEffect(() => {\n const updateContent = async (markdown: string) => {\n const blocks = await editor.tryParseMarkdownToBlocks(markdown);\n if (!areBlocksEqual(blocks, editor.document)) {\n editor.replaceBlocks(editor.document, blocks);\n }\n };\n\n if (markdownContent && hasInitializedFromMarkdown.current !== markdownContent) {\n hasInitializedFromMarkdown.current = markdownContent;\n updateContent(markdownContent).then(() => handleChange());\n }\n }, [markdownContent, editor]);\n\n // Update editor content when diff content changes, but only if different\n // Prevent unnecessary replaceBlocks calls that reset scroll/cursor.\n const previousContentHashRef = useRef<string | null>(null);\n useEffect(() => {\n if (!processedContent || !editor) return;\n const hash = JSON.stringify(processedContent);\n if (previousContentHashRef.current === hash) return; // no changes\n const currentHash = JSON.stringify(editor.document);\n if (currentHash === hash) {\n previousContentHashRef.current = hash;\n return; // already in sync\n }\n editor.replaceBlocks(editor.document, processedContent as PartialBlock[]);\n previousContentHashRef.current = hash;\n }, [processedContent, editor]);\n\n // Handle audio received from whisper transcription\n const handleAudioReceived = useCallback(\n (message: string) => {\n try {\n // Ensure the editor has focus\n const editorElement = editorRef.current?.querySelector('[contenteditable=\"true\"]') as HTMLElement;\n if (editorElement && document.activeElement !== editorElement) {\n editorElement.focus();\n }\n\n // Insert the transcribed text at the current cursor position\n editor.insertInlineContent(message);\n } catch (error) {\n console.error(\"Error inserting transcribed text:\", error);\n // Fallback: try to insert at the end of the document\n try {\n const blocks = editor.document;\n if (blocks.length > 0) {\n const lastBlock = blocks[blocks.length - 1];\n editor.setTextCursorPosition(lastBlock.id, \"end\");\n editor.insertInlineContent(message);\n }\n } catch (fallbackError) {\n console.error(\"Fallback insertion also failed:\", fallbackError);\n }\n }\n },\n [editor],\n );\n\n return (\n <div ref={editorRef} className={cn(bordered ? \"rounded-md border\" : \"\", \"w-full\")}>\n <BlockNoteView\n editor={editor}\n onChange={handleChange}\n editable={onChange !== undefined}\n formattingToolbar={false}\n theme=\"light\"\n className={cn(`BlockNoteView ${onChange ? \"min-h-96 p-4\" : \"\"}`, className, size === \"sm\" && \"small\")}\n >\n <BlockNoteEditorFormattingToolbar />\n </BlockNoteView>\n </div>\n );\n}\n","\"use client\";\n\nimport {\n BasicTextStyleButton,\n BlockTypeSelect,\n CreateLinkButton,\n FileCaptionButton,\n FileReplaceButton,\n FormattingToolbar,\n FormattingToolbarController,\n TextAlignButton,\n} from \"@blocknote/react\";\n\nexport function BlockNoteEditorFormattingToolbar() {\n return (\n <FormattingToolbarController\n formattingToolbar={() => (\n <FormattingToolbar>\n <BlockTypeSelect key={\"blockTypeSelect\"} />\n\n <FileCaptionButton key={\"fileCaptionButton\"} />\n <FileReplaceButton key={\"replaceFileButton\"} />\n\n <BasicTextStyleButton basicTextStyle={\"bold\"} key={\"boldStyleButton\"} />\n <BasicTextStyleButton basicTextStyle={\"italic\"} key={\"italicStyleButton\"} />\n <BasicTextStyleButton basicTextStyle={\"underline\"} key={\"underlineStyleButton\"} />\n <BasicTextStyleButton basicTextStyle={\"strike\"} key={\"strikeStyleButton\"} />\n\n <TextAlignButton textAlignment={\"left\"} key={\"textAlignLeftButton\"} />\n <TextAlignButton textAlignment={\"center\"} key={\"textAlignCenterButton\"} />\n <TextAlignButton textAlignment={\"right\"} key={\"textAlignRightButton\"} />\n\n <CreateLinkButton key={\"createLinkButton\"} />\n </FormattingToolbar>\n )}\n />\n );\n}\n"]}
@@ -1,28 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
-
3
- var _chunk7QVYU63Ejs = require('./chunk-7QVYU63E.js');
4
-
5
- // src/roles/config.ts
6
- var _roleId = null;
7
- function configureRoles(roleId) {
8
- _roleId = roleId;
9
- }
10
- _chunk7QVYU63Ejs.__name.call(void 0, configureRoles, "configureRoles");
11
- function getRoleId() {
12
- if (!_roleId) {
13
- throw new Error("Roles not configured. Call configureRoles() at app startup.");
14
- }
15
- return _roleId;
16
- }
17
- _chunk7QVYU63Ejs.__name.call(void 0, getRoleId, "getRoleId");
18
- function isRolesConfigured() {
19
- return _roleId !== null;
20
- }
21
- _chunk7QVYU63Ejs.__name.call(void 0, isRolesConfigured, "isRolesConfigured");
22
-
23
-
24
-
25
-
26
-
27
- exports.configureRoles = configureRoles; exports.getRoleId = getRoleId; exports.isRolesConfigured = isRolesConfigured;
28
- //# sourceMappingURL=chunk-4HCRAOS5.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-4HCRAOS5.js","../src/roles/config.ts"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACA;ACOA,IAAI,QAAA,EAA+B,IAAA;AAc5B,SAAS,cAAA,CAAe,MAAA,EAA4B;AACzD,EAAA,QAAA,EAAU,MAAA;AACZ;AAFgB,qCAAA,cAAA,EAAA,gBAAA,CAAA;AAQT,SAAS,SAAA,CAAA,EAA0B;AACxC,EAAA,GAAA,CAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,KAAA,CAAM,6DAA6D,CAAA;AAAA,EAC/E;AACA,EAAA,OAAO,OAAA;AACT;AALgB,qCAAA,SAAA,EAAA,WAAA,CAAA;AAUT,SAAS,iBAAA,CAAA,EAA6B;AAC3C,EAAA,OAAO,QAAA,IAAY,IAAA;AACrB;AAFgB,qCAAA,iBAAA,EAAA,mBAAA,CAAA;ADtBhB;AACA;AACE;AACA;AACA;AACF,sHAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-4HCRAOS5.js","sourcesContent":[null,"/**\n * Role ID configuration interface\n * Apps provide their role IDs via configureRoles()\n */\nexport interface RoleIdConfig {\n Administrator: string;\n CompanyAdministrator: string;\n [key: string]: string; // Allow additional roles\n}\n\n// Private storage for the injected role IDs\nlet _roleId: RoleIdConfig | null = null;\n\n/**\n * Configure role IDs for the library\n * Call this at app startup to provide role ID constants\n *\n * @example\n * ```typescript\n * import { configureRoles } from \"@carlonicora/nextjs-jsonapi\";\n * import { RoleId } from \"@phlow/shared\";\n *\n * configureRoles(RoleId);\n * ```\n */\nexport function configureRoles(roleId: RoleIdConfig): void {\n _roleId = roleId;\n}\n\n/**\n * Get configured role IDs\n * @throws Error if roles not configured\n */\nexport function getRoleId(): RoleIdConfig {\n if (!_roleId) {\n throw new Error(\"Roles not configured. Call configureRoles() at app startup.\");\n }\n return _roleId;\n}\n\n/**\n * Check if roles have been configured\n */\nexport function isRolesConfigured(): boolean {\n return _roleId !== null;\n}\n"]}