@carlonicora/nextjs-jsonapi 6.22.0 → 6.24.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 (181) hide show
  1. package/dist/{BlockNoteEditor-2XSIQCEB.mjs → BlockNoteEditor-ENDOVTAW.mjs} +8 -8
  2. package/dist/{BlockNoteEditor-HW3TK7SM.js → BlockNoteEditor-MONT74RQ.js} +23 -23
  3. package/dist/{BlockNoteEditor-HW3TK7SM.js.map → BlockNoteEditor-MONT74RQ.js.map} +1 -1
  4. package/dist/{BlockNoteViewer-2UDFTXRS.mjs → BlockNoteViewer-2TJZ6JET.mjs} +6 -6
  5. package/dist/{BlockNoteViewer-4OHBRE4Q.js → BlockNoteViewer-K2HBF3IP.js} +7 -7
  6. package/dist/{BlockNoteViewer-4OHBRE4Q.js.map → BlockNoteViewer-K2HBF3IP.js.map} +1 -1
  7. package/dist/{JsonApiRequest-IKKHWCPB.mjs → JsonApiRequest-ADLBJ5RX.mjs} +2 -2
  8. package/dist/JsonApiRequest-KC6DOHKT.js +26 -0
  9. package/dist/{JsonApiRequest-G4J2WTSU.js.map → JsonApiRequest-KC6DOHKT.js.map} +1 -1
  10. package/dist/billing/index.js +495 -495
  11. package/dist/billing/index.mjs +7 -7
  12. package/dist/{chunk-N5ZE2Z6I.js → chunk-53SD4YRF.js} +5 -5
  13. package/dist/{chunk-N5ZE2Z6I.js.map → chunk-53SD4YRF.js.map} +1 -1
  14. package/dist/{chunk-4RA5PRXX.mjs → chunk-7OIWOPM5.mjs} +2 -2
  15. package/dist/{chunk-WCEYT3GG.js → chunk-A5M3MORY.js} +6 -3
  16. package/dist/chunk-A5M3MORY.js.map +1 -0
  17. package/dist/{chunk-FXRRQ7Q6.js → chunk-BDWV4KYR.js} +1224 -1221
  18. package/dist/chunk-BDWV4KYR.js.map +1 -0
  19. package/dist/{chunk-AUD6ZLBB.mjs → chunk-BE6UMM5X.mjs} +13 -8
  20. package/dist/chunk-BE6UMM5X.mjs.map +1 -0
  21. package/dist/{chunk-KV4N7DEG.js → chunk-BQ2WAG4K.js} +29 -24
  22. package/dist/chunk-BQ2WAG4K.js.map +1 -0
  23. package/dist/{chunk-OQQ7CZWT.js → chunk-GMMDXINC.js} +12 -12
  24. package/dist/{chunk-OQQ7CZWT.js.map → chunk-GMMDXINC.js.map} +1 -1
  25. package/dist/{chunk-ZB6OYIMB.js → chunk-HN7L6RRW.js} +1296 -1093
  26. package/dist/{chunk-DPXOPLQP.mjs.map → chunk-HN7L6RRW.js.map} +1 -1
  27. package/dist/{chunk-JSHLBRFV.mjs → chunk-N2BFT7KI.mjs} +2 -2
  28. package/dist/chunk-N2BFT7KI.mjs.map +1 -0
  29. package/dist/{chunk-EFQIMPCJ.mjs → chunk-OZADFYE7.mjs} +13 -10
  30. package/dist/chunk-OZADFYE7.mjs.map +1 -0
  31. package/dist/{chunk-YWLSIIE6.js → chunk-P7L6OFX5.js} +11 -11
  32. package/dist/{chunk-YWLSIIE6.js.map → chunk-P7L6OFX5.js.map} +1 -1
  33. package/dist/{chunk-GM4VZTWL.js → chunk-RCOKQ3R4.js} +14 -8
  34. package/dist/chunk-RCOKQ3R4.js.map +1 -0
  35. package/dist/{chunk-M3N7LPHX.mjs → chunk-S7SPAC6X.mjs} +6 -3
  36. package/dist/chunk-S7SPAC6X.mjs.map +1 -0
  37. package/dist/{chunk-54K2CZ2F.js → chunk-SO3YUCL6.js} +4 -4
  38. package/dist/{chunk-54K2CZ2F.js.map → chunk-SO3YUCL6.js.map} +1 -1
  39. package/dist/{chunk-DPXOPLQP.mjs → chunk-T6G2F2BK.mjs} +220 -17
  40. package/dist/chunk-T6G2F2BK.mjs.map +1 -0
  41. package/dist/{chunk-G2UIQSNJ.mjs → chunk-TMV7TL7O.mjs} +4 -4
  42. package/dist/{chunk-BD6ARGGI.js → chunk-TNTCLVUR.js} +15 -15
  43. package/dist/{chunk-BD6ARGGI.js.map → chunk-TNTCLVUR.js.map} +1 -1
  44. package/dist/{chunk-QIEF7HIL.mjs → chunk-VNUT2D27.mjs} +2 -2
  45. package/dist/{chunk-KTGKW72G.mjs → chunk-W4ML6D2X.mjs} +2 -2
  46. package/dist/{chunk-MQ7TXALH.mjs → chunk-YMCL3JXZ.mjs} +14 -8
  47. package/dist/chunk-YMCL3JXZ.mjs.map +1 -0
  48. package/dist/{chunk-QGVVF77L.js → chunk-YSE2Z4RB.js} +11 -11
  49. package/dist/{chunk-QGVVF77L.js.map → chunk-YSE2Z4RB.js.map} +1 -1
  50. package/dist/{chunk-A3RB47X4.mjs → chunk-YTDGYI62.mjs} +3 -3
  51. package/dist/client/JsonApiClient.d.ts +5 -0
  52. package/dist/client/JsonApiClient.d.ts.map +1 -1
  53. package/dist/client/index.js +8 -8
  54. package/dist/client/index.mjs +7 -7
  55. package/dist/client/request.d.ts +5 -0
  56. package/dist/client/request.d.ts.map +1 -1
  57. package/dist/components/forms/EditorSheet.d.ts +6 -1
  58. package/dist/components/forms/EditorSheet.d.ts.map +1 -1
  59. package/dist/components/index.js +8 -8
  60. package/dist/components/index.mjs +7 -7
  61. package/dist/contexts/index.js +8 -8
  62. package/dist/contexts/index.mjs +7 -7
  63. package/dist/core/abstracts/AbstractService.d.ts +5 -0
  64. package/dist/core/abstracts/AbstractService.d.ts.map +1 -1
  65. package/dist/core/abstracts/ClientAbstractService.d.ts +5 -0
  66. package/dist/core/abstracts/ClientAbstractService.d.ts.map +1 -1
  67. package/dist/core/index.d.ts +2 -0
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +24 -6
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/core/index.mjs +23 -5
  72. package/dist/core/registry/ModuleRegistry.d.ts +3 -0
  73. package/dist/core/registry/ModuleRegistry.d.ts.map +1 -1
  74. package/dist/email-automations/index.js +121 -121
  75. package/dist/email-automations/index.mjs +7 -7
  76. package/dist/features/analytics/index.js +139 -139
  77. package/dist/features/analytics/index.mjs +7 -7
  78. package/dist/features/analytics/server.js +9 -9
  79. package/dist/features/analytics/server.mjs +7 -7
  80. package/dist/features/blog/index.js +154 -154
  81. package/dist/features/blog/index.mjs +7 -7
  82. package/dist/features/blog/server.js +27 -27
  83. package/dist/features/blog/server.mjs +6 -6
  84. package/dist/features/discord-connection/data/discord-connect-confirmation.d.ts +11 -0
  85. package/dist/features/discord-connection/data/discord-connect-confirmation.d.ts.map +1 -0
  86. package/dist/features/discord-connection/data/discord-connect-confirmation.interface.d.ts +14 -0
  87. package/dist/features/discord-connection/data/discord-connect-confirmation.interface.d.ts.map +1 -0
  88. package/dist/features/discord-connection/data/discord-connect-confirmation.service.d.ts +10 -0
  89. package/dist/features/discord-connection/data/discord-connect-confirmation.service.d.ts.map +1 -0
  90. package/dist/features/discord-connection/data/discord-connect-intent.d.ts +11 -0
  91. package/dist/features/discord-connection/data/discord-connect-intent.d.ts.map +1 -0
  92. package/dist/features/discord-connection/data/discord-connect-intent.interface.d.ts +15 -0
  93. package/dist/features/discord-connection/data/discord-connect-intent.interface.d.ts.map +1 -0
  94. package/dist/features/discord-connection/data/discord-connect-intent.service.d.ts +11 -0
  95. package/dist/features/discord-connection/data/discord-connect-intent.service.d.ts.map +1 -0
  96. package/dist/features/discord-connection/data/discord-connection.d.ts +14 -0
  97. package/dist/features/discord-connection/data/discord-connection.d.ts.map +1 -0
  98. package/dist/features/discord-connection/data/discord-connection.interface.d.ts +10 -0
  99. package/dist/features/discord-connection/data/discord-connection.interface.d.ts.map +1 -0
  100. package/dist/features/discord-connection/data/discord-connection.service.d.ts +12 -0
  101. package/dist/features/discord-connection/data/discord-connection.service.d.ts.map +1 -0
  102. package/dist/features/discord-connection/data/index.d.ts +10 -0
  103. package/dist/features/discord-connection/data/index.d.ts.map +1 -0
  104. package/dist/features/discord-connection/discord-connection.module.d.ts +5 -0
  105. package/dist/features/discord-connection/discord-connection.module.d.ts.map +1 -0
  106. package/dist/features/discord-connection/index.d.ts +3 -0
  107. package/dist/features/discord-connection/index.d.ts.map +1 -0
  108. package/dist/features/help/index.js +41 -41
  109. package/dist/features/help/index.mjs +7 -7
  110. package/dist/features/tokenusage/index.js +130 -130
  111. package/dist/features/tokenusage/index.mjs +7 -7
  112. package/dist/index.d.ts +1 -1
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +27 -7
  115. package/dist/index.js.map +1 -1
  116. package/dist/index.mjs +26 -6
  117. package/dist/local-transport-MJPOKPTU.js +15 -0
  118. package/dist/{local-transport-4YDJ6FQG.js.map → local-transport-MJPOKPTU.js.map} +1 -1
  119. package/dist/{local-transport-C7YTA4I7.mjs → local-transport-RVD4FZGA.mjs} +5 -5
  120. package/dist/offline/index.js +51 -51
  121. package/dist/offline/index.mjs +6 -6
  122. package/dist/{request-66FGJIHB.mjs → request-4AWGPIGH.mjs} +2 -2
  123. package/dist/{request-6W6UGKJV.js → request-H5FZBZA2.js} +3 -3
  124. package/dist/{request-6W6UGKJV.js.map → request-H5FZBZA2.js.map} +1 -1
  125. package/dist/server/index.js +8 -8
  126. package/dist/server/index.mjs +7 -7
  127. package/dist/unified/JsonApiRequest.d.ts +5 -0
  128. package/dist/unified/JsonApiRequest.d.ts.map +1 -1
  129. package/dist/write-through-7I3LA2WN.mjs +15 -0
  130. package/dist/write-through-HE2QSOVI.js +15 -0
  131. package/dist/{write-through-BAPS24GL.js.map → write-through-HE2QSOVI.js.map} +1 -1
  132. package/package.json +1 -1
  133. package/src/client/JsonApiClient.ts +10 -0
  134. package/src/client/__tests__/request.credentials.spec.ts +103 -0
  135. package/src/client/request.ts +9 -0
  136. package/src/components/forms/EditorSheet.tsx +8 -0
  137. package/src/components/forms/__tests__/EditorSheet.spec.tsx +30 -0
  138. package/src/core/abstracts/AbstractService.ts +10 -0
  139. package/src/core/abstracts/ClientAbstractService.ts +10 -0
  140. package/src/core/index.ts +3 -0
  141. package/src/core/registry/ModuleRegistry.ts +4 -0
  142. package/src/features/discord-connection/data/__tests__/DiscordConnection.spec.ts +114 -0
  143. package/src/features/discord-connection/data/discord-connect-confirmation.interface.ts +16 -0
  144. package/src/features/discord-connection/data/discord-connect-confirmation.service.ts +21 -0
  145. package/src/features/discord-connection/data/discord-connect-confirmation.ts +46 -0
  146. package/src/features/discord-connection/data/discord-connect-intent.interface.ts +16 -0
  147. package/src/features/discord-connection/data/discord-connect-intent.service.ts +20 -0
  148. package/src/features/discord-connection/data/discord-connect-intent.ts +42 -0
  149. package/src/features/discord-connection/data/discord-connection.interface.ts +10 -0
  150. package/src/features/discord-connection/data/discord-connection.service.ts +17 -0
  151. package/src/features/discord-connection/data/discord-connection.ts +41 -0
  152. package/src/features/discord-connection/data/index.ts +9 -0
  153. package/src/features/discord-connection/discord-connection.module.ts +28 -0
  154. package/src/features/discord-connection/index.ts +2 -0
  155. package/src/index.ts +1 -1
  156. package/src/unified/JsonApiRequest.ts +14 -0
  157. package/dist/JsonApiRequest-G4J2WTSU.js +0 -26
  158. package/dist/chunk-AUD6ZLBB.mjs.map +0 -1
  159. package/dist/chunk-EFQIMPCJ.mjs.map +0 -1
  160. package/dist/chunk-FXRRQ7Q6.js.map +0 -1
  161. package/dist/chunk-GM4VZTWL.js.map +0 -1
  162. package/dist/chunk-JSHLBRFV.mjs.map +0 -1
  163. package/dist/chunk-KV4N7DEG.js.map +0 -1
  164. package/dist/chunk-M3N7LPHX.mjs.map +0 -1
  165. package/dist/chunk-MQ7TXALH.mjs.map +0 -1
  166. package/dist/chunk-WCEYT3GG.js.map +0 -1
  167. package/dist/chunk-ZB6OYIMB.js.map +0 -1
  168. package/dist/local-transport-4YDJ6FQG.js +0 -15
  169. package/dist/write-through-BAPS24GL.js +0 -15
  170. package/dist/write-through-IWQKXYHE.mjs +0 -15
  171. /package/dist/{BlockNoteEditor-2XSIQCEB.mjs.map → BlockNoteEditor-ENDOVTAW.mjs.map} +0 -0
  172. /package/dist/{BlockNoteViewer-2UDFTXRS.mjs.map → BlockNoteViewer-2TJZ6JET.mjs.map} +0 -0
  173. /package/dist/{JsonApiRequest-IKKHWCPB.mjs.map → JsonApiRequest-ADLBJ5RX.mjs.map} +0 -0
  174. /package/dist/{chunk-4RA5PRXX.mjs.map → chunk-7OIWOPM5.mjs.map} +0 -0
  175. /package/dist/{chunk-G2UIQSNJ.mjs.map → chunk-TMV7TL7O.mjs.map} +0 -0
  176. /package/dist/{chunk-QIEF7HIL.mjs.map → chunk-VNUT2D27.mjs.map} +0 -0
  177. /package/dist/{chunk-KTGKW72G.mjs.map → chunk-W4ML6D2X.mjs.map} +0 -0
  178. /package/dist/{chunk-A3RB47X4.mjs.map → chunk-YTDGYI62.mjs.map} +0 -0
  179. /package/dist/{local-transport-C7YTA4I7.mjs.map → local-transport-RVD4FZGA.mjs.map} +0 -0
  180. /package/dist/{request-66FGJIHB.mjs.map → request-4AWGPIGH.mjs.map} +0 -0
  181. /package/dist/{write-through-IWQKXYHE.mjs.map → write-through-7I3LA2WN.mjs.map} +0 -0
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  AbstractService
3
- } from "./chunk-DPXOPLQP.mjs";
3
+ } from "./chunk-T6G2F2BK.mjs";
4
4
  import {
5
5
  EndpointCreator,
6
6
  Modules,
7
7
  useI18nTranslations
8
- } from "./chunk-JSHLBRFV.mjs";
8
+ } from "./chunk-N2BFT7KI.mjs";
9
9
  import {
10
10
  ENV,
11
11
  setBootstrapper
12
- } from "./chunk-MQ7TXALH.mjs";
12
+ } from "./chunk-YMCL3JXZ.mjs";
13
13
  import {
14
14
  __name
15
15
  } from "./chunk-PAWJFY3S.mjs";
@@ -342,4 +342,4 @@ export {
342
342
  ACTION_TYPES,
343
343
  RbacService
344
344
  };
345
- //# sourceMappingURL=chunk-G2UIQSNJ.mjs.map
345
+ //# sourceMappingURL=chunk-TMV7TL7O.mjs.map
@@ -1,15 +1,15 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkZB6OYIMBjs = require('./chunk-ZB6OYIMB.js');
3
+ var _chunkHN7L6RRWjs = require('./chunk-HN7L6RRW.js');
4
4
 
5
5
 
6
6
 
7
7
 
8
- var _chunkYWLSIIE6js = require('./chunk-YWLSIIE6.js');
8
+ var _chunkP7L6OFX5js = require('./chunk-P7L6OFX5.js');
9
9
 
10
10
 
11
11
 
12
- var _chunkGM4VZTWLjs = require('./chunk-GM4VZTWL.js');
12
+ var _chunkRCOKQ3R4js = require('./chunk-RCOKQ3R4.js');
13
13
 
14
14
 
15
15
  var _chunk7QVYU63Ejs = require('./chunk-7QVYU63E.js');
@@ -38,7 +38,7 @@ function configureJsonApi(config) {
38
38
  _setStaticHelpContent(helpContent);
39
39
  }
40
40
  if (config.bootstrapper) {
41
- _chunkGM4VZTWLjs.setBootstrapper.call(void 0, config.bootstrapper);
41
+ _chunkRCOKQ3R4js.setBootstrapper.call(void 0, config.bootstrapper);
42
42
  config.bootstrapper();
43
43
  }
44
44
  }
@@ -51,19 +51,19 @@ function getApiUrl() {
51
51
  if (_optionalChain([_clientConfig, 'optionalAccess', _ => _.apiUrl])) {
52
52
  return _clientConfig.apiUrl;
53
53
  }
54
- return _chunkGM4VZTWLjs.ENV.API_URL;
54
+ return _chunkRCOKQ3R4js.ENV.API_URL;
55
55
  }
56
56
  _chunk7QVYU63Ejs.__name.call(void 0, getApiUrl, "getApiUrl");
57
57
  function getPublicApiUrl() {
58
- return _chunkGM4VZTWLjs.ENV.API_URL;
58
+ return _chunkRCOKQ3R4js.ENV.API_URL;
59
59
  }
60
60
  _chunk7QVYU63Ejs.__name.call(void 0, getPublicApiUrl, "getPublicApiUrl");
61
61
  function getAppUrl() {
62
62
  if (_optionalChain([_clientConfig, 'optionalAccess', _2 => _2.appUrl])) {
63
63
  return _clientConfig.appUrl;
64
64
  }
65
- if (_chunkGM4VZTWLjs.ENV.APP_URL_ALTERNATE) {
66
- return _chunkGM4VZTWLjs.ENV.APP_URL_ALTERNATE;
65
+ if (_chunkRCOKQ3R4js.ENV.APP_URL_ALTERNATE) {
66
+ return _chunkRCOKQ3R4js.ENV.APP_URL_ALTERNATE;
67
67
  }
68
68
  if (typeof window !== "undefined") {
69
69
  return window.location.origin;
@@ -126,7 +126,7 @@ function getWaitlistConfig() {
126
126
  }
127
127
  _chunk7QVYU63Ejs.__name.call(void 0, getWaitlistConfig, "getWaitlistConfig");
128
128
  function useWaitlistText() {
129
- const t = _chunkYWLSIIE6js.useI18nTranslations.call(void 0, );
129
+ const t = _chunkP7L6OFX5js.useI18nTranslations.call(void 0, );
130
130
  const translate = getWaitlistConfig().translate === true;
131
131
  return (value) => {
132
132
  if (!value) return void 0;
@@ -264,7 +264,7 @@ var COMPANY_ADMINISTRATOR_ROLE_ID = "2e1eee00-6cba-4506-9059-ccd24e4ea5b0";
264
264
  var ACTION_TYPES = ["read", "create", "update", "delete"];
265
265
 
266
266
  // src/features/rbac/data/RbacService.ts
267
- var RbacService = class extends _chunkZB6OYIMBjs.AbstractService {
267
+ var RbacService = class extends _chunkHN7L6RRWjs.AbstractService {
268
268
  static {
269
269
  _chunk7QVYU63Ejs.__name.call(void 0, this, "RbacService");
270
270
  }
@@ -275,9 +275,9 @@ var RbacService = class extends _chunkZB6OYIMBjs.AbstractService {
275
275
  * Dev-only endpoint — see class header.
276
276
  */
277
277
  static async fetchMatrix() {
278
- const endpoint = new (0, _chunkYWLSIIE6js.EndpointCreator)({ endpoint: _chunkYWLSIIE6js.Modules.RbacMatrix }).generate();
278
+ const endpoint = new (0, _chunkP7L6OFX5js.EndpointCreator)({ endpoint: _chunkP7L6OFX5js.Modules.RbacMatrix }).generate();
279
279
  const model = await this.callApi({
280
- type: _chunkYWLSIIE6js.Modules.RbacMatrix,
280
+ type: _chunkP7L6OFX5js.Modules.RbacMatrix,
281
281
  method: "GET" /* GET */,
282
282
  endpoint
283
283
  });
@@ -297,9 +297,9 @@ var RbacService = class extends _chunkZB6OYIMBjs.AbstractService {
297
297
  * Dev-only endpoint — see class header.
298
298
  */
299
299
  static async saveMatrix(args) {
300
- const endpoint = new (0, _chunkYWLSIIE6js.EndpointCreator)({ endpoint: _chunkYWLSIIE6js.Modules.RbacMatrix }).generate();
300
+ const endpoint = new (0, _chunkP7L6OFX5js.EndpointCreator)({ endpoint: _chunkP7L6OFX5js.Modules.RbacMatrix }).generate();
301
301
  const model = await this.callApi({
302
- type: _chunkYWLSIIE6js.Modules.RbacMatrix,
302
+ type: _chunkP7L6OFX5js.Modules.RbacMatrix,
303
303
  method: "PUT" /* PUT */,
304
304
  endpoint,
305
305
  input: args
@@ -342,4 +342,4 @@ var RbacService = class extends _chunkZB6OYIMBjs.AbstractService {
342
342
 
343
343
 
344
344
  exports._getStaticHelpContent = _getStaticHelpContent; exports.configureJsonApi = configureJsonApi; exports.configureClientConfig = configureClientConfig; exports.getApiUrl = getApiUrl; exports.getPublicApiUrl = getPublicApiUrl; exports.getAppUrl = getAppUrl; exports.getTrackablePages = getTrackablePages; exports.getStripePublishableKey = getStripePublishableKey; exports.configureLogin = configureLogin; exports.isDiscordAuthEnabled = isDiscordAuthEnabled; exports.isGoogleAuthEnabled = isGoogleAuthEnabled; exports.isInternalAuthEnabled = isInternalAuthEnabled; exports.isRegistrationAllowed = isRegistrationAllowed; exports.getRegistrationMode = getRegistrationMode; exports.configureWaitlist = configureWaitlist; exports.getWaitlistConfig = getWaitlistConfig; exports.useWaitlistText = useWaitlistText; exports.configureReferral = configureReferral; exports.getReferralConfig = getReferralConfig; exports.isReferralEnabled = isReferralEnabled; exports.SIGNUP_SOURCE_COOKIE = SIGNUP_SOURCE_COOKIE; exports.SIGNUP_SOURCE_COOKIE_MAX_AGE = SIGNUP_SOURCE_COOKIE_MAX_AGE; exports.SIGNUP_SOURCE_FIELDS = SIGNUP_SOURCE_FIELDS; exports.readSignupSourceFromLocation = readSignupSourceFromLocation; exports.captureSignupSource = captureSignupSource; exports.getSignupSource = getSignupSource; exports.COMPANY_ADMINISTRATOR_ROLE_ID = COMPANY_ADMINISTRATOR_ROLE_ID; exports.ACTION_TYPES = ACTION_TYPES; exports.RbacService = RbacService;
345
- //# sourceMappingURL=chunk-BD6ARGGI.js.map
345
+ //# sourceMappingURL=chunk-TNTCLVUR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-BD6ARGGI.js","../src/core/registry/helpStore.ts","../src/client/config.ts","../src/login/config.ts","../src/features/waitlist/config/waitlist.config.ts","../src/features/referral/config.ts","../src/features/signup-source/signup-source.ts","../src/features/rbac/data/RbacTypes.ts","../src/features/rbac/data/RbacService.ts"],"names":[],"mappings":"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","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-BD6ARGGI.js","sourcesContent":[null,"/**\n * Centralized help-content store accessible from client and server contexts.\n * Uses a globalThis Symbol key to persist across HMR/Turbopack reloads and to\n * bridge between the client-side `configureJsonApi` (in `client/config.ts`)\n * and the HelpProvider context. Holds the brand-only HelpContentConfig.\n *\n * NO external dependencies to avoid circular imports.\n *\n * Pattern mirrors `bootstrapStore.ts`.\n */\n\nconst HELP_CONTENT_KEY = Symbol.for(\"nextjs-jsonapi:helpContent\");\n\nconst globalStore = globalThis as unknown as {\n [HELP_CONTENT_KEY]?: unknown | null;\n};\n\nif (globalStore[HELP_CONTENT_KEY] === undefined) {\n globalStore[HELP_CONTENT_KEY] = null;\n}\n\nexport function _setStaticHelpContent(cfg: unknown | null): void {\n globalStore[HELP_CONTENT_KEY] = cfg;\n}\n\nexport function _getStaticHelpContent<T = unknown>(): T | null {\n return (globalStore[HELP_CONTENT_KEY] as T | null) ?? null;\n}\n","\"use client\";\n\nimport { ModuleWithPermissions } from \"../permissions/types\";\nimport { ENV } from \"../core/env\";\nimport { setBootstrapper } from \"../core/registry/bootstrapStore\";\nimport { _setStaticHelpContent } from \"../core/registry/helpStore\";\nimport type { HelpContentConfig } from \"../features/help/interfaces/help-content-config.interface\";\n\n// Config storage for client-side contexts\nlet _clientConfig: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n bootstrapper?: () => void;\n additionalHeaders?: Record<string, string>;\n stripePublishableKey?: string;\n} | null = null;\n\n/**\n * Configure the JSON:API client. This is the main configuration function.\n * This is typically called during app initialization.\n * @param config.helpContent - Optional help-content config (brand only). Forwarded to the help feature's globalThis-backed store; not stored on the client config.\n */\nexport function configureJsonApi(config: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n bootstrapper?: () => void;\n additionalHeaders?: Record<string, string>;\n stripePublishableKey?: string;\n helpContent?: HelpContentConfig;\n}): void {\n const { helpContent, ...rest } = config;\n _clientConfig = rest;\n if (helpContent) {\n _setStaticHelpContent(helpContent);\n }\n // Register and call bootstrapper to register all modules\n if (config.bootstrapper) {\n setBootstrapper(config.bootstrapper);\n config.bootstrapper();\n }\n}\n\n/**\n * Configure the client config. This is typically called during app initialization.\n * @deprecated Use configureJsonApi instead\n */\nexport function configureClientConfig(config: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n}): void {\n _clientConfig = config;\n}\n\n/**\n * Get the configured API URL.\n *\n * This may resolve to an internal/private host (e.g. a docker-network\n * hostname) when configured to do so for SSR fetches. Do NOT use this for\n * URLs that are rendered into HTML and followed by the browser — use\n * `getPublicApiUrl()` instead.\n */\nexport function getApiUrl(): string {\n if (_clientConfig?.apiUrl) {\n return _clientConfig.apiUrl;\n }\n return ENV.API_URL;\n}\n\n/**\n * Get the public-facing API URL.\n *\n * Always sourced from `NEXT_PUBLIC_API_URL` so it is identical on server\n * and client, and reachable from the user's browser. Use for any URL that\n * gets rendered into HTML the browser will navigate to (links, redirects,\n * OAuth hrefs).\n */\nexport function getPublicApiUrl(): string {\n return ENV.API_URL;\n}\n\n/**\n * Get the configured app URL.\n */\nexport function getAppUrl(): string {\n if (_clientConfig?.appUrl) {\n return _clientConfig.appUrl;\n }\n if (ENV.APP_URL_ALTERNATE) {\n return ENV.APP_URL_ALTERNATE;\n }\n if (typeof window !== \"undefined\") {\n return window.location.origin;\n }\n return \"\";\n}\n\n/**\n * Get the configured trackable pages.\n */\nexport function getTrackablePages(): ModuleWithPermissions[] {\n return _clientConfig?.trackablePages ?? [];\n}\n\n/**\n * Get the configured Stripe publishable key.\n */\nexport function getStripePublishableKey(): string | undefined {\n return _clientConfig?.stripePublishableKey;\n}\n","let _useDiscordAuth: boolean = false;\nlet _useGoogleAuth: boolean = false;\nlet _useInternalAuth: boolean = true;\nlet _allowRegistration: boolean = true;\nlet _registrationMode: \"open\" | \"closed\" | \"waitlist\" = \"open\";\n\nexport type RegistrationMode = \"open\" | \"closed\" | \"waitlist\";\n\nexport interface LoginConfig {\n discordClientId?: string;\n googleClientId?: string;\n useInternalAuth?: boolean;\n allowRegistration?: boolean;\n registrationMode?: RegistrationMode;\n}\n\nexport function configureLogin(params: LoginConfig): void {\n _useDiscordAuth = !!params.discordClientId;\n _useGoogleAuth = !!params.googleClientId;\n _useInternalAuth = params.useInternalAuth ?? true;\n _allowRegistration = params.allowRegistration ?? true;\n _registrationMode = params.registrationMode ?? \"open\";\n}\n\nexport function isDiscordAuthEnabled(): boolean {\n return _useDiscordAuth;\n}\n\nexport function isGoogleAuthEnabled(): boolean {\n return _useGoogleAuth;\n}\n\nexport function isInternalAuthEnabled(): boolean {\n return _useInternalAuth;\n}\n\nexport function isRegistrationAllowed(): boolean {\n return _allowRegistration;\n}\n\nexport function getRegistrationMode(): RegistrationMode {\n return _registrationMode;\n}\n","import { useI18nTranslations } from \"../../../i18n\";\n\nexport type QuestionnaireFieldType = \"text\" | \"textarea\" | \"select\" | \"checkbox\";\n\nexport interface QuestionnaireOption {\n value: string;\n label: string;\n description?: string;\n}\n\nexport interface QuestionnaireField {\n id: string;\n type: QuestionnaireFieldType;\n label: string;\n description?: string;\n placeholder?: string;\n required?: boolean;\n options?: QuestionnaireOption[];\n}\n\nexport interface WaitlistConfig {\n questionnaire?: QuestionnaireField[];\n heroTitle?: string;\n heroSubtitle?: string;\n heroDescription?: string;\n benefits?: string[];\n /**\n * When true, every text above (hero title, subtitle, description, benefits and\n * the questionnaire's labels, descriptions, placeholders and option labels) is\n * a message key and renders through `t()`. Defaults to false: the strings\n * render as given.\n */\n translate?: boolean;\n}\n\nlet _waitlistConfig: WaitlistConfig = {};\n\nexport function configureWaitlist(config: WaitlistConfig): void {\n _waitlistConfig = config;\n}\n\nexport function getWaitlistConfig(): WaitlistConfig {\n return _waitlistConfig;\n}\n\n/**\n * Resolves a waitlist config text: `t(value)` when the config sets\n * `translate`, the value itself otherwise. Empty values stay undefined.\n */\nexport function useWaitlistText(): (value?: string) => string | undefined {\n const t = useI18nTranslations();\n const translate = getWaitlistConfig().translate === true;\n\n return (value?: string) => {\n if (!value) return undefined;\n return translate ? t(value) : value;\n };\n}\n","/**\n * Configuration interface for frontend referral feature.\n */\nexport interface ReferralConfig {\n /**\n * Whether the referral feature is enabled.\n * When false, components render nothing and hooks return null.\n * @default false\n */\n enabled?: boolean;\n\n /**\n * Name of the cookie used to store referral codes.\n * @default \"referral_code\"\n */\n cookieName?: string;\n\n /**\n * Number of days the referral cookie is valid.\n * @default 30\n */\n cookieDays?: number;\n\n /**\n * Query parameter name for referral code in URL.\n * @default \"ref\"\n */\n urlParamName?: string;\n\n /**\n * Base URL for referral links.\n * @default window.location.origin (client-side only)\n */\n referralUrlBase?: string;\n\n /**\n * Path to append to base URL for referral links.\n * @default \"/\"\n */\n referralPath?: string;\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_REFERRAL_CONFIG: Required<ReferralConfig> = {\n enabled: false,\n cookieName: \"referral_code\",\n cookieDays: 30,\n urlParamName: \"ref\",\n referralUrlBase: \"\",\n referralPath: \"/\",\n};\n\n// Private storage for configuration\nlet _referralConfig: Required<ReferralConfig> = { ...DEFAULT_REFERRAL_CONFIG };\n\n/**\n * Configure referral feature settings.\n * Call this at app startup to enable and configure referral functionality.\n *\n * @example\n * ```typescript\n * import { configureReferral } from \"@carlonicora/nextjs-jsonapi\";\n *\n * configureReferral({\n * enabled: process.env.NEXT_PUBLIC_REFERRAL_ENABLED === 'true',\n * cookieDays: 30,\n * });\n * ```\n */\nexport function configureReferral(config: ReferralConfig): void {\n _referralConfig = { ...DEFAULT_REFERRAL_CONFIG, ...config };\n}\n\n/**\n * Get the current referral configuration.\n * @internal\n */\nexport function getReferralConfig(): Required<ReferralConfig> {\n return _referralConfig;\n}\n\n/**\n * Check if referral feature is enabled.\n */\nexport function isReferralEnabled(): boolean {\n return _referralConfig.enabled;\n}\n","export type SignupSource = {\n sourceRef?: string;\n sourceUtmSource?: string;\n sourceUtmMedium?: string;\n sourceUtmCampaign?: string;\n sourceReferrer?: string;\n sourceLandingPath?: string;\n};\n\nexport const SIGNUP_SOURCE_COOKIE = \"signup_source\";\nexport const SIGNUP_SOURCE_COOKIE_MAX_AGE = 2592000;\n\n/** The six source fields, in display order. */\nexport const SIGNUP_SOURCE_FIELDS: readonly (keyof SignupSource)[] = [\n \"sourceRef\",\n \"sourceUtmSource\",\n \"sourceUtmMedium\",\n \"sourceUtmCampaign\",\n \"sourceReferrer\",\n \"sourceLandingPath\",\n];\n\nconst SIGNUP_SOURCE_MAX_LENGTH = 200;\n\n// First touch for the current page session. Survives client navigations, lost on a full reload.\nlet memorySource: SignupSource | undefined;\n\nfunction clean(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n return trimmed.slice(0, SIGNUP_SOURCE_MAX_LENGTH);\n}\n\nfunction sanitise(input: unknown): SignupSource | undefined {\n if (!input || typeof input !== \"object\") return undefined;\n const result: SignupSource = {};\n for (const field of SIGNUP_SOURCE_FIELDS) {\n const value = clean((input as Record<string, unknown>)[field]);\n if (value !== undefined) result[field] = value;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Pure. Reads ref and utm_source/medium/campaign from the URL, the referrer host when it is not ownHost,\n * and the landing path. Returns undefined for a direct visit (no ref, no UTM, no external referrer).\n */\nexport function readSignupSourceFromLocation(params: {\n url: string;\n referrer: string;\n ownHost: string;\n}): SignupSource | undefined {\n let url: URL;\n try {\n url = new URL(params.url);\n } catch {\n return undefined;\n }\n\n const sourceRef = clean(url.searchParams.get(\"ref\"));\n const sourceUtmSource = clean(url.searchParams.get(\"utm_source\"));\n const sourceUtmMedium = clean(url.searchParams.get(\"utm_medium\"));\n const sourceUtmCampaign = clean(url.searchParams.get(\"utm_campaign\"));\n\n let sourceReferrer: string | undefined;\n if (params.referrer) {\n try {\n const referrerHost = new URL(params.referrer).host;\n if (referrerHost && referrerHost !== params.ownHost) sourceReferrer = clean(referrerHost);\n } catch {\n sourceReferrer = undefined;\n }\n }\n\n if (!sourceRef && !sourceUtmSource && !sourceUtmMedium && !sourceUtmCampaign && !sourceReferrer) return undefined;\n\n return sanitise({\n sourceRef,\n sourceUtmSource,\n sourceUtmMedium,\n sourceUtmCampaign,\n sourceReferrer,\n sourceLandingPath: url.pathname,\n });\n}\n\nfunction readSignupSourceCookie(): SignupSource | undefined {\n if (typeof document === \"undefined\") return undefined;\n const cookies = document.cookie ? document.cookie.split(\"; \") : [];\n for (const cookie of cookies) {\n const separator = cookie.indexOf(\"=\");\n if (separator === -1) continue;\n if (cookie.slice(0, separator) !== SIGNUP_SOURCE_COOKIE) continue;\n const value = cookie.slice(separator + 1);\n if (!value) return undefined;\n try {\n return sanitise(JSON.parse(decodeURIComponent(value)));\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\nfunction writeSignupSourceCookie(source: SignupSource): void {\n document.cookie = `${SIGNUP_SOURCE_COOKIE}=${encodeURIComponent(JSON.stringify(source))}; path=/; max-age=${SIGNUP_SOURCE_COOKIE_MAX_AGE}; SameSite=Lax`;\n}\n\n/**\n * First touch: an existing in-memory value or cookie is never overwritten.\n * Writes the cookie only when persist is true and no cookie exists yet.\n */\nexport function captureSignupSource(params: { persist: boolean }): void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n const existingCookie = readSignupSourceCookie();\n\n if (!memorySource) {\n memorySource =\n existingCookie ??\n readSignupSourceFromLocation({\n url: window.location.href,\n referrer: document.referrer,\n ownHost: window.location.host,\n });\n }\n\n if (params.persist && !existingCookie && memorySource) writeSignupSourceCookie(memorySource);\n}\n\n/** The in-memory value, else the cookie value, else undefined. */\nexport function getSignupSource(): SignupSource | undefined {\n return memorySource ?? readSignupSourceCookie();\n}\n","export const COMPANY_ADMINISTRATOR_ROLE_ID = \"2e1eee00-6cba-4506-9059-ccd24e4ea5b0\";\n\nexport type PermissionValue = boolean | string;\n\nexport type ActionType = \"read\" | \"create\" | \"update\" | \"delete\";\n\nexport const ACTION_TYPES: ActionType[] = [\"read\", \"create\", \"update\", \"delete\"];\n\n/** The permissions object shape used by both Module and PermissionMapping entities */\nexport type PermissionsMap = {\n create?: PermissionValue;\n read?: PermissionValue;\n update?: PermissionValue;\n delete?: PermissionValue;\n};\n\n/**\n * Declarative-RBAC matrix types.\n *\n * Mirror of the library types defined in\n * `packages/nestjs-neo4jsonapi/src/foundations/rbac/dsl/types.ts`.\n * Frontend does not import from backend, so the shape is redefined here.\n *\n * A `PermToken` represents a single permission entry:\n * - `scope: true` → unconditional (e.g. full read of the module)\n * - `scope: false` → nothing (rarely used, mostly a placeholder)\n * - `scope: \"path\"` → scoped by relationship path (e.g. \"orders.account\")\n */\nexport type PermToken = { action: string; scope: boolean | string };\n\n/**\n * A per-module block of the matrix. Always has a `default` row (permissions\n * granted to every role). Additional keys are role IDs → role-specific\n * permission tokens that are unioned with `default` to produce the effective\n * permissions for that role in that module.\n */\nexport type RbacModuleBlock = { default: PermToken[] } & Record<string, PermToken[]>;\n\n/**\n * The full RBAC matrix as served by the dev endpoint `GET /_dev/rbac/matrix`.\n * Keys are module IDs; values are module blocks.\n */\nexport type RbacMatrix = Record<string, RbacModuleBlock>;\n","import { AbstractService, EndpointCreator, HttpMethod, Modules } from \"../../../core\";\nimport type { RbacMatrixModel } from \"./RbacMatrixModel\";\nimport type { RbacMatrix } from \"./RbacTypes\";\n\n/**\n * RbacService — fetches RBAC configuration for the admin UI.\n *\n * Declarative-matrix methods (`fetchMatrix`, `saveMatrix`) talk to the\n * dev-only endpoints added in\n * `packages/nestjs-neo4jsonapi/.../rbac-dev.controller.ts`. The controller\n * speaks JSON:API (singleton resource with `type: \"rbac-matrix\"`, `id:\n * \"singleton\"`), so these methods go through the standard `callApi()`\n * pipeline like every other service in the codebase.\n *\n * The backend only registers these routes when `devMode` is enabled on\n * `RbacModule.register` (see `apps/api/src/features/features.modules.ts`).\n * In production the routes return 404; callers should guard with a dev-mode\n * check.\n */\nexport class RbacService extends AbstractService {\n /**\n * Fetch the current RBAC matrix plus each module's known BFS relationship\n * paths (used by the permission picker as scope suggestions).\n *\n * Dev-only endpoint — see class header.\n */\n static async fetchMatrix(): Promise<{\n matrix: RbacMatrix;\n modulePaths: Record<string, readonly string[]>;\n }> {\n const endpoint = new EndpointCreator({ endpoint: Modules.RbacMatrix }).generate();\n\n const model = await this.callApi<RbacMatrixModel>({\n type: Modules.RbacMatrix,\n method: HttpMethod.GET,\n endpoint,\n });\n\n return {\n matrix: model.matrix ?? {},\n modulePaths: model.modulePaths ?? {},\n };\n }\n\n /**\n * Persist a matrix back to the declarative `permissions.ts` file.\n *\n * The backend serializes the matrix to formatted TypeScript using the\n * provided `roleNames` / `moduleNames` lookup tables (so the emitted file\n * references `RoleId.X` / `ModuleId.X` rather than raw UUIDs) and writes\n * it to `outputPath` (absolute, or relative to the repo root).\n *\n * Dev-only endpoint — see class header.\n */\n static async saveMatrix(args: {\n matrix: RbacMatrix;\n roleNames: Record<string, string>;\n moduleNames: Record<string, string>;\n outputPath: string;\n }): Promise<{ bytesWritten: number; path: string }> {\n const endpoint = new EndpointCreator({ endpoint: Modules.RbacMatrix }).generate();\n\n const model = await this.callApi<RbacMatrixModel>({\n type: Modules.RbacMatrix,\n method: HttpMethod.PUT,\n endpoint,\n input: args,\n });\n\n return {\n bytesWritten: model.bytesWritten ?? 0,\n path: model.path ?? \"\",\n };\n }\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-TNTCLVUR.js","../src/core/registry/helpStore.ts","../src/client/config.ts","../src/login/config.ts","../src/features/waitlist/config/waitlist.config.ts","../src/features/referral/config.ts","../src/features/signup-source/signup-source.ts","../src/features/rbac/data/RbacTypes.ts","../src/features/rbac/data/RbacService.ts"],"names":[],"mappings":"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","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-TNTCLVUR.js","sourcesContent":[null,"/**\n * Centralized help-content store accessible from client and server contexts.\n * Uses a globalThis Symbol key to persist across HMR/Turbopack reloads and to\n * bridge between the client-side `configureJsonApi` (in `client/config.ts`)\n * and the HelpProvider context. Holds the brand-only HelpContentConfig.\n *\n * NO external dependencies to avoid circular imports.\n *\n * Pattern mirrors `bootstrapStore.ts`.\n */\n\nconst HELP_CONTENT_KEY = Symbol.for(\"nextjs-jsonapi:helpContent\");\n\nconst globalStore = globalThis as unknown as {\n [HELP_CONTENT_KEY]?: unknown | null;\n};\n\nif (globalStore[HELP_CONTENT_KEY] === undefined) {\n globalStore[HELP_CONTENT_KEY] = null;\n}\n\nexport function _setStaticHelpContent(cfg: unknown | null): void {\n globalStore[HELP_CONTENT_KEY] = cfg;\n}\n\nexport function _getStaticHelpContent<T = unknown>(): T | null {\n return (globalStore[HELP_CONTENT_KEY] as T | null) ?? null;\n}\n","\"use client\";\n\nimport { ModuleWithPermissions } from \"../permissions/types\";\nimport { ENV } from \"../core/env\";\nimport { setBootstrapper } from \"../core/registry/bootstrapStore\";\nimport { _setStaticHelpContent } from \"../core/registry/helpStore\";\nimport type { HelpContentConfig } from \"../features/help/interfaces/help-content-config.interface\";\n\n// Config storage for client-side contexts\nlet _clientConfig: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n bootstrapper?: () => void;\n additionalHeaders?: Record<string, string>;\n stripePublishableKey?: string;\n} | null = null;\n\n/**\n * Configure the JSON:API client. This is the main configuration function.\n * This is typically called during app initialization.\n * @param config.helpContent - Optional help-content config (brand only). Forwarded to the help feature's globalThis-backed store; not stored on the client config.\n */\nexport function configureJsonApi(config: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n bootstrapper?: () => void;\n additionalHeaders?: Record<string, string>;\n stripePublishableKey?: string;\n helpContent?: HelpContentConfig;\n}): void {\n const { helpContent, ...rest } = config;\n _clientConfig = rest;\n if (helpContent) {\n _setStaticHelpContent(helpContent);\n }\n // Register and call bootstrapper to register all modules\n if (config.bootstrapper) {\n setBootstrapper(config.bootstrapper);\n config.bootstrapper();\n }\n}\n\n/**\n * Configure the client config. This is typically called during app initialization.\n * @deprecated Use configureJsonApi instead\n */\nexport function configureClientConfig(config: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n}): void {\n _clientConfig = config;\n}\n\n/**\n * Get the configured API URL.\n *\n * This may resolve to an internal/private host (e.g. a docker-network\n * hostname) when configured to do so for SSR fetches. Do NOT use this for\n * URLs that are rendered into HTML and followed by the browser — use\n * `getPublicApiUrl()` instead.\n */\nexport function getApiUrl(): string {\n if (_clientConfig?.apiUrl) {\n return _clientConfig.apiUrl;\n }\n return ENV.API_URL;\n}\n\n/**\n * Get the public-facing API URL.\n *\n * Always sourced from `NEXT_PUBLIC_API_URL` so it is identical on server\n * and client, and reachable from the user's browser. Use for any URL that\n * gets rendered into HTML the browser will navigate to (links, redirects,\n * OAuth hrefs).\n */\nexport function getPublicApiUrl(): string {\n return ENV.API_URL;\n}\n\n/**\n * Get the configured app URL.\n */\nexport function getAppUrl(): string {\n if (_clientConfig?.appUrl) {\n return _clientConfig.appUrl;\n }\n if (ENV.APP_URL_ALTERNATE) {\n return ENV.APP_URL_ALTERNATE;\n }\n if (typeof window !== \"undefined\") {\n return window.location.origin;\n }\n return \"\";\n}\n\n/**\n * Get the configured trackable pages.\n */\nexport function getTrackablePages(): ModuleWithPermissions[] {\n return _clientConfig?.trackablePages ?? [];\n}\n\n/**\n * Get the configured Stripe publishable key.\n */\nexport function getStripePublishableKey(): string | undefined {\n return _clientConfig?.stripePublishableKey;\n}\n","let _useDiscordAuth: boolean = false;\nlet _useGoogleAuth: boolean = false;\nlet _useInternalAuth: boolean = true;\nlet _allowRegistration: boolean = true;\nlet _registrationMode: \"open\" | \"closed\" | \"waitlist\" = \"open\";\n\nexport type RegistrationMode = \"open\" | \"closed\" | \"waitlist\";\n\nexport interface LoginConfig {\n discordClientId?: string;\n googleClientId?: string;\n useInternalAuth?: boolean;\n allowRegistration?: boolean;\n registrationMode?: RegistrationMode;\n}\n\nexport function configureLogin(params: LoginConfig): void {\n _useDiscordAuth = !!params.discordClientId;\n _useGoogleAuth = !!params.googleClientId;\n _useInternalAuth = params.useInternalAuth ?? true;\n _allowRegistration = params.allowRegistration ?? true;\n _registrationMode = params.registrationMode ?? \"open\";\n}\n\nexport function isDiscordAuthEnabled(): boolean {\n return _useDiscordAuth;\n}\n\nexport function isGoogleAuthEnabled(): boolean {\n return _useGoogleAuth;\n}\n\nexport function isInternalAuthEnabled(): boolean {\n return _useInternalAuth;\n}\n\nexport function isRegistrationAllowed(): boolean {\n return _allowRegistration;\n}\n\nexport function getRegistrationMode(): RegistrationMode {\n return _registrationMode;\n}\n","import { useI18nTranslations } from \"../../../i18n\";\n\nexport type QuestionnaireFieldType = \"text\" | \"textarea\" | \"select\" | \"checkbox\";\n\nexport interface QuestionnaireOption {\n value: string;\n label: string;\n description?: string;\n}\n\nexport interface QuestionnaireField {\n id: string;\n type: QuestionnaireFieldType;\n label: string;\n description?: string;\n placeholder?: string;\n required?: boolean;\n options?: QuestionnaireOption[];\n}\n\nexport interface WaitlistConfig {\n questionnaire?: QuestionnaireField[];\n heroTitle?: string;\n heroSubtitle?: string;\n heroDescription?: string;\n benefits?: string[];\n /**\n * When true, every text above (hero title, subtitle, description, benefits and\n * the questionnaire's labels, descriptions, placeholders and option labels) is\n * a message key and renders through `t()`. Defaults to false: the strings\n * render as given.\n */\n translate?: boolean;\n}\n\nlet _waitlistConfig: WaitlistConfig = {};\n\nexport function configureWaitlist(config: WaitlistConfig): void {\n _waitlistConfig = config;\n}\n\nexport function getWaitlistConfig(): WaitlistConfig {\n return _waitlistConfig;\n}\n\n/**\n * Resolves a waitlist config text: `t(value)` when the config sets\n * `translate`, the value itself otherwise. Empty values stay undefined.\n */\nexport function useWaitlistText(): (value?: string) => string | undefined {\n const t = useI18nTranslations();\n const translate = getWaitlistConfig().translate === true;\n\n return (value?: string) => {\n if (!value) return undefined;\n return translate ? t(value) : value;\n };\n}\n","/**\n * Configuration interface for frontend referral feature.\n */\nexport interface ReferralConfig {\n /**\n * Whether the referral feature is enabled.\n * When false, components render nothing and hooks return null.\n * @default false\n */\n enabled?: boolean;\n\n /**\n * Name of the cookie used to store referral codes.\n * @default \"referral_code\"\n */\n cookieName?: string;\n\n /**\n * Number of days the referral cookie is valid.\n * @default 30\n */\n cookieDays?: number;\n\n /**\n * Query parameter name for referral code in URL.\n * @default \"ref\"\n */\n urlParamName?: string;\n\n /**\n * Base URL for referral links.\n * @default window.location.origin (client-side only)\n */\n referralUrlBase?: string;\n\n /**\n * Path to append to base URL for referral links.\n * @default \"/\"\n */\n referralPath?: string;\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_REFERRAL_CONFIG: Required<ReferralConfig> = {\n enabled: false,\n cookieName: \"referral_code\",\n cookieDays: 30,\n urlParamName: \"ref\",\n referralUrlBase: \"\",\n referralPath: \"/\",\n};\n\n// Private storage for configuration\nlet _referralConfig: Required<ReferralConfig> = { ...DEFAULT_REFERRAL_CONFIG };\n\n/**\n * Configure referral feature settings.\n * Call this at app startup to enable and configure referral functionality.\n *\n * @example\n * ```typescript\n * import { configureReferral } from \"@carlonicora/nextjs-jsonapi\";\n *\n * configureReferral({\n * enabled: process.env.NEXT_PUBLIC_REFERRAL_ENABLED === 'true',\n * cookieDays: 30,\n * });\n * ```\n */\nexport function configureReferral(config: ReferralConfig): void {\n _referralConfig = { ...DEFAULT_REFERRAL_CONFIG, ...config };\n}\n\n/**\n * Get the current referral configuration.\n * @internal\n */\nexport function getReferralConfig(): Required<ReferralConfig> {\n return _referralConfig;\n}\n\n/**\n * Check if referral feature is enabled.\n */\nexport function isReferralEnabled(): boolean {\n return _referralConfig.enabled;\n}\n","export type SignupSource = {\n sourceRef?: string;\n sourceUtmSource?: string;\n sourceUtmMedium?: string;\n sourceUtmCampaign?: string;\n sourceReferrer?: string;\n sourceLandingPath?: string;\n};\n\nexport const SIGNUP_SOURCE_COOKIE = \"signup_source\";\nexport const SIGNUP_SOURCE_COOKIE_MAX_AGE = 2592000;\n\n/** The six source fields, in display order. */\nexport const SIGNUP_SOURCE_FIELDS: readonly (keyof SignupSource)[] = [\n \"sourceRef\",\n \"sourceUtmSource\",\n \"sourceUtmMedium\",\n \"sourceUtmCampaign\",\n \"sourceReferrer\",\n \"sourceLandingPath\",\n];\n\nconst SIGNUP_SOURCE_MAX_LENGTH = 200;\n\n// First touch for the current page session. Survives client navigations, lost on a full reload.\nlet memorySource: SignupSource | undefined;\n\nfunction clean(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n return trimmed.slice(0, SIGNUP_SOURCE_MAX_LENGTH);\n}\n\nfunction sanitise(input: unknown): SignupSource | undefined {\n if (!input || typeof input !== \"object\") return undefined;\n const result: SignupSource = {};\n for (const field of SIGNUP_SOURCE_FIELDS) {\n const value = clean((input as Record<string, unknown>)[field]);\n if (value !== undefined) result[field] = value;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Pure. Reads ref and utm_source/medium/campaign from the URL, the referrer host when it is not ownHost,\n * and the landing path. Returns undefined for a direct visit (no ref, no UTM, no external referrer).\n */\nexport function readSignupSourceFromLocation(params: {\n url: string;\n referrer: string;\n ownHost: string;\n}): SignupSource | undefined {\n let url: URL;\n try {\n url = new URL(params.url);\n } catch {\n return undefined;\n }\n\n const sourceRef = clean(url.searchParams.get(\"ref\"));\n const sourceUtmSource = clean(url.searchParams.get(\"utm_source\"));\n const sourceUtmMedium = clean(url.searchParams.get(\"utm_medium\"));\n const sourceUtmCampaign = clean(url.searchParams.get(\"utm_campaign\"));\n\n let sourceReferrer: string | undefined;\n if (params.referrer) {\n try {\n const referrerHost = new URL(params.referrer).host;\n if (referrerHost && referrerHost !== params.ownHost) sourceReferrer = clean(referrerHost);\n } catch {\n sourceReferrer = undefined;\n }\n }\n\n if (!sourceRef && !sourceUtmSource && !sourceUtmMedium && !sourceUtmCampaign && !sourceReferrer) return undefined;\n\n return sanitise({\n sourceRef,\n sourceUtmSource,\n sourceUtmMedium,\n sourceUtmCampaign,\n sourceReferrer,\n sourceLandingPath: url.pathname,\n });\n}\n\nfunction readSignupSourceCookie(): SignupSource | undefined {\n if (typeof document === \"undefined\") return undefined;\n const cookies = document.cookie ? document.cookie.split(\"; \") : [];\n for (const cookie of cookies) {\n const separator = cookie.indexOf(\"=\");\n if (separator === -1) continue;\n if (cookie.slice(0, separator) !== SIGNUP_SOURCE_COOKIE) continue;\n const value = cookie.slice(separator + 1);\n if (!value) return undefined;\n try {\n return sanitise(JSON.parse(decodeURIComponent(value)));\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\nfunction writeSignupSourceCookie(source: SignupSource): void {\n document.cookie = `${SIGNUP_SOURCE_COOKIE}=${encodeURIComponent(JSON.stringify(source))}; path=/; max-age=${SIGNUP_SOURCE_COOKIE_MAX_AGE}; SameSite=Lax`;\n}\n\n/**\n * First touch: an existing in-memory value or cookie is never overwritten.\n * Writes the cookie only when persist is true and no cookie exists yet.\n */\nexport function captureSignupSource(params: { persist: boolean }): void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return;\n\n const existingCookie = readSignupSourceCookie();\n\n if (!memorySource) {\n memorySource =\n existingCookie ??\n readSignupSourceFromLocation({\n url: window.location.href,\n referrer: document.referrer,\n ownHost: window.location.host,\n });\n }\n\n if (params.persist && !existingCookie && memorySource) writeSignupSourceCookie(memorySource);\n}\n\n/** The in-memory value, else the cookie value, else undefined. */\nexport function getSignupSource(): SignupSource | undefined {\n return memorySource ?? readSignupSourceCookie();\n}\n","export const COMPANY_ADMINISTRATOR_ROLE_ID = \"2e1eee00-6cba-4506-9059-ccd24e4ea5b0\";\n\nexport type PermissionValue = boolean | string;\n\nexport type ActionType = \"read\" | \"create\" | \"update\" | \"delete\";\n\nexport const ACTION_TYPES: ActionType[] = [\"read\", \"create\", \"update\", \"delete\"];\n\n/** The permissions object shape used by both Module and PermissionMapping entities */\nexport type PermissionsMap = {\n create?: PermissionValue;\n read?: PermissionValue;\n update?: PermissionValue;\n delete?: PermissionValue;\n};\n\n/**\n * Declarative-RBAC matrix types.\n *\n * Mirror of the library types defined in\n * `packages/nestjs-neo4jsonapi/src/foundations/rbac/dsl/types.ts`.\n * Frontend does not import from backend, so the shape is redefined here.\n *\n * A `PermToken` represents a single permission entry:\n * - `scope: true` → unconditional (e.g. full read of the module)\n * - `scope: false` → nothing (rarely used, mostly a placeholder)\n * - `scope: \"path\"` → scoped by relationship path (e.g. \"orders.account\")\n */\nexport type PermToken = { action: string; scope: boolean | string };\n\n/**\n * A per-module block of the matrix. Always has a `default` row (permissions\n * granted to every role). Additional keys are role IDs → role-specific\n * permission tokens that are unioned with `default` to produce the effective\n * permissions for that role in that module.\n */\nexport type RbacModuleBlock = { default: PermToken[] } & Record<string, PermToken[]>;\n\n/**\n * The full RBAC matrix as served by the dev endpoint `GET /_dev/rbac/matrix`.\n * Keys are module IDs; values are module blocks.\n */\nexport type RbacMatrix = Record<string, RbacModuleBlock>;\n","import { AbstractService, EndpointCreator, HttpMethod, Modules } from \"../../../core\";\nimport type { RbacMatrixModel } from \"./RbacMatrixModel\";\nimport type { RbacMatrix } from \"./RbacTypes\";\n\n/**\n * RbacService — fetches RBAC configuration for the admin UI.\n *\n * Declarative-matrix methods (`fetchMatrix`, `saveMatrix`) talk to the\n * dev-only endpoints added in\n * `packages/nestjs-neo4jsonapi/.../rbac-dev.controller.ts`. The controller\n * speaks JSON:API (singleton resource with `type: \"rbac-matrix\"`, `id:\n * \"singleton\"`), so these methods go through the standard `callApi()`\n * pipeline like every other service in the codebase.\n *\n * The backend only registers these routes when `devMode` is enabled on\n * `RbacModule.register` (see `apps/api/src/features/features.modules.ts`).\n * In production the routes return 404; callers should guard with a dev-mode\n * check.\n */\nexport class RbacService extends AbstractService {\n /**\n * Fetch the current RBAC matrix plus each module's known BFS relationship\n * paths (used by the permission picker as scope suggestions).\n *\n * Dev-only endpoint — see class header.\n */\n static async fetchMatrix(): Promise<{\n matrix: RbacMatrix;\n modulePaths: Record<string, readonly string[]>;\n }> {\n const endpoint = new EndpointCreator({ endpoint: Modules.RbacMatrix }).generate();\n\n const model = await this.callApi<RbacMatrixModel>({\n type: Modules.RbacMatrix,\n method: HttpMethod.GET,\n endpoint,\n });\n\n return {\n matrix: model.matrix ?? {},\n modulePaths: model.modulePaths ?? {},\n };\n }\n\n /**\n * Persist a matrix back to the declarative `permissions.ts` file.\n *\n * The backend serializes the matrix to formatted TypeScript using the\n * provided `roleNames` / `moduleNames` lookup tables (so the emitted file\n * references `RoleId.X` / `ModuleId.X` rather than raw UUIDs) and writes\n * it to `outputPath` (absolute, or relative to the repo root).\n *\n * Dev-only endpoint — see class header.\n */\n static async saveMatrix(args: {\n matrix: RbacMatrix;\n roleNames: Record<string, string>;\n moduleNames: Record<string, string>;\n outputPath: string;\n }): Promise<{ bytesWritten: number; path: string }> {\n const endpoint = new EndpointCreator({ endpoint: Modules.RbacMatrix }).generate();\n\n const model = await this.callApi<RbacMatrixModel>({\n type: Modules.RbacMatrix,\n method: HttpMethod.PUT,\n endpoint,\n input: args,\n });\n\n return {\n bytesWritten: model.bytesWritten ?? 0,\n path: model.path ?? \"\",\n };\n }\n}\n"]}
@@ -8,7 +8,7 @@ import {
8
8
  ENV,
9
9
  JsonApiDataFactory,
10
10
  translateResponse
11
- } from "./chunk-MQ7TXALH.mjs";
11
+ } from "./chunk-YMCL3JXZ.mjs";
12
12
  import {
13
13
  __name
14
14
  } from "./chunk-PAWJFY3S.mjs";
@@ -201,4 +201,4 @@ export {
201
201
  ServerJsonApiPatch,
202
202
  ServerJsonApiDelete
203
203
  };
204
- //# sourceMappingURL=chunk-QIEF7HIL.mjs.map
204
+ //# sourceMappingURL=chunk-VNUT2D27.mjs.map
@@ -10,7 +10,7 @@ import {
10
10
  matchPattern,
11
11
  rootIdForResource,
12
12
  splitApiUrl
13
- } from "./chunk-A3RB47X4.mjs";
13
+ } from "./chunk-YTDGYI62.mjs";
14
14
  import {
15
15
  OfflineUnavailableError,
16
16
  getOfflineConfig,
@@ -230,4 +230,4 @@ export {
230
230
  waitingRecordKeys,
231
231
  writeThrough
232
232
  };
233
- //# sourceMappingURL=chunk-KTGKW72G.mjs.map
233
+ //# sourceMappingURL=chunk-W4ML6D2X.mjs.map
@@ -292,7 +292,7 @@ __name(getToken, "getToken");
292
292
  async function makeRequest(params) {
293
293
  if (typeof window !== "undefined") {
294
294
  if (!_directFetch) {
295
- const clientModule = await import("./request-66FGJIHB.mjs");
295
+ const clientModule = await import("./request-4AWGPIGH.mjs");
296
296
  _directFetch = clientModule.directFetch;
297
297
  }
298
298
  return _directFetch({
@@ -303,7 +303,8 @@ async function makeRequest(params) {
303
303
  files: params.files,
304
304
  companyId: params.companyId,
305
305
  language: params.language,
306
- additionalHeaders: params.additionalHeaders
306
+ additionalHeaders: params.additionalHeaders,
307
+ credentials: params.credentials
307
308
  });
308
309
  } else {
309
310
  if (!_serverRequest) {
@@ -375,7 +376,8 @@ async function JsonApiGet(params) {
375
376
  cache: params.classKey.cache,
376
377
  companyId: params.companyId,
377
378
  language: params.language,
378
- additionalHeaders: _staticConfig?.additionalHeaders
379
+ additionalHeaders: _staticConfig?.additionalHeaders,
380
+ credentials: params.credentials
379
381
  });
380
382
  return translateResponse({
381
383
  classKey: params.classKey,
@@ -410,7 +412,8 @@ async function JsonApiPost(params) {
410
412
  files: params.files,
411
413
  companyId: params.companyId,
412
414
  language: params.language,
413
- additionalHeaders: _staticConfig?.additionalHeaders
415
+ additionalHeaders: _staticConfig?.additionalHeaders,
416
+ credentials: params.credentials
414
417
  });
415
418
  return translateResponse({
416
419
  classKey: params.responseType ?? params.classKey,
@@ -437,7 +440,8 @@ async function JsonApiPut(params) {
437
440
  files: params.files,
438
441
  companyId: params.companyId,
439
442
  language: params.language,
440
- additionalHeaders: _staticConfig?.additionalHeaders
443
+ additionalHeaders: _staticConfig?.additionalHeaders,
444
+ credentials: params.credentials
441
445
  });
442
446
  return translateResponse({
443
447
  classKey: params.responseType ?? params.classKey,
@@ -464,7 +468,8 @@ async function JsonApiPatch(params) {
464
468
  files: params.files,
465
469
  companyId: params.companyId,
466
470
  language: params.language,
467
- additionalHeaders: _staticConfig?.additionalHeaders
471
+ additionalHeaders: _staticConfig?.additionalHeaders,
472
+ credentials: params.credentials
468
473
  });
469
474
  return translateResponse({
470
475
  classKey: params.responseType ?? params.classKey,
@@ -483,7 +488,8 @@ async function JsonApiDelete(params) {
483
488
  token,
484
489
  companyId: params.companyId,
485
490
  language: params.language,
486
- additionalHeaders: _staticConfig?.additionalHeaders
491
+ additionalHeaders: _staticConfig?.additionalHeaders,
492
+ credentials: params.credentials
487
493
  });
488
494
  return translateResponse({
489
495
  classKey: params.responseType ?? params.classKey,
@@ -516,4 +522,4 @@ export {
516
522
  JsonApiPatch,
517
523
  JsonApiDelete
518
524
  };
519
- //# sourceMappingURL=chunk-MQ7TXALH.mjs.map
525
+ //# sourceMappingURL=chunk-YMCL3JXZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/env.ts","../src/core/registry/DataClassRegistry.ts","../src/core/factories/JsonApiDataFactory.ts","../src/core/registry/bootstrapStore.ts","../src/core/utils/translateResponse.ts","../src/unified/JsonApiRequest.ts"],"sourcesContent":["/**\n * The single place in this package that reads `process.env`.\n *\n * Everything else imports {@link ENV}. Centralising the reads keeps every\n * default in one place — the same contract `base.config.ts` provides on the\n * NestJS side — instead of scattering `process.env.X || \"…\"` across hooks,\n * clients and components where the fallbacks silently drift apart.\n *\n * WHY THE READS MUST STAY LITERAL: Next.js inlines `NEXT_PUBLIC_*` by textual\n * substitution at build time, replacing the exact expression\n * `process.env.NEXT_PUBLIC_FOO` with a string literal. A computed lookup\n * (`process.env[key]`) is NOT substituted and reads as `undefined` in the\n * browser bundle. Every entry below therefore spells its variable out in full,\n * and new entries must do the same.\n *\n * WHY GETTERS AND NOT PLAIN PROPERTIES: every call site this replaced read\n * `process.env` at CALL time, not at import time. A plain property would freeze\n * the value when the module is first imported, which breaks any consumer that\n * assigns the variable after boot — the package's own tests do exactly that.\n * Getters keep the read lazy while leaving the expression literal, so the build\n * time substitution still applies.\n *\n * Because that substitution happens before the code runs, no reference to\n * `process` survives into the client bundle — so this module is safe to import\n * from client components, server components, route handlers and middleware\n * alike. It deliberately carries no `\"use client\"` directive for that reason.\n *\n * Values are normalised (empty string rather than `undefined`, booleans rather\n * than string comparisons) so callers never repeat the parsing. Callers that\n * must distinguish \"unset\" from \"set to empty\" — the URL getters, which throw a\n * configuration error — check for an empty string.\n */\nexport const ENV = {\n /** Public API base URL (NEXT_PUBLIC_API_URL). Empty when unset. */\n get API_URL(): string {\n return process.env.NEXT_PUBLIC_API_URL ?? \"\";\n },\n /** Public app base URL (NEXT_PUBLIC_ADDRESS). Empty when unset. */\n get APP_URL(): string {\n return process.env.NEXT_PUBLIC_ADDRESS ?? \"\";\n },\n /**\n * Alternative app base URL (NEXT_PUBLIC_APP_URL), used only by\n * `client/config.ts`'s `getAppUrl()` before it falls back to\n * `window.location.origin`. Empty when unset.\n */\n get APP_URL_ALTERNATE(): string {\n return process.env.NEXT_PUBLIC_APP_URL ?? \"\";\n },\n /** Web-push VAPID public key (NEXT_PUBLIC_VAPID_PUBLIC_KEY). Empty when unset. */\n get VAPID_PUBLIC_KEY(): string {\n return process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY ?? \"\";\n },\n /** Google Maps JS key (NEXT_PUBLIC_GOOGLE_MAPS_API_KEY). Empty disables autocomplete. */\n get GOOGLE_MAPS_API_KEY(): string {\n return process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY ?? \"\";\n },\n /**\n * NEXT_PUBLIC_PRIVATE_INSTALLATION === \"true\", case-insensitively\n * (default false). A private installation is a single-tenant deployment.\n */\n get PRIVATE_INSTALLATION(): boolean {\n return process.env.NEXT_PUBLIC_PRIVATE_INSTALLATION?.toLowerCase() === \"true\";\n },\n /** NODE_ENV === \"production\" — set by the Next build, not by `.env`. */\n get IS_PRODUCTION(): boolean {\n return process.env.NODE_ENV === \"production\";\n },\n /** NODE_ENV === \"development\" — gates verbose client-side diagnostics. */\n get IS_DEVELOPMENT(): boolean {\n return process.env.NODE_ENV === \"development\";\n },\n};\n","import { ApiDataInterface } from \"../interfaces/ApiDataInterface\";\nimport { ApiRequestDataTypeInterface } from \"../interfaces/ApiRequestDataTypeInterface\";\n\nexport class DataClassRegistry {\n // Use Map with string key (module.name) for reliable lookup\n // String keys are stable across HMR and module re-evaluations\n // Note: WeakMap with object identity was tried but fails during Next.js navigation\n // because module re-evaluation creates new object instances with different identity\n private static _map = new Map<string, { new (): ApiDataInterface }>();\n\n public static registerObjectClass(\n key: ApiRequestDataTypeInterface,\n classConstructor: { new (): ApiDataInterface },\n ): void {\n // Last registration wins. An earlier version skipped re-registration, which\n // silently pinned the registry to the FIRST constructor seen by the process.\n // In dev that made a long-lived `next dev` server keep rehydrating with the\n // pre-edit class after any model change, so SSR produced a different tree\n // from the freshly bundled client and React threw a hydration mismatch.\n // Production is unaffected either way: bootstrap runs once per process.\n this._map.set(key.name, classConstructor);\n }\n\n public static get(classKey: ApiRequestDataTypeInterface): {\n new (): ApiDataInterface;\n } {\n const response = this._map.get(classKey.name);\n if (!response) {\n throw new Error(\n `Class not registered for key: ${typeof classKey === \"string\" ? classKey : classKey.name}. Ensure bootstrap() was called.`,\n );\n }\n\n return response;\n }\n\n /**\n * Get class constructor by JSON:API type name.\n * Used for polymorphic rehydration where the type is determined at runtime.\n */\n public static getByJsonApiType(typeName: string): { new (): ApiDataInterface } | undefined {\n return this._map.get(typeName);\n }\n\n /**\n * Bootstrap the registry with all modules.\n * This is a convenience method for apps to register all their modules at once.\n *\n * @param modules - An object with module definitions (like the app's Modules class)\n */\n public static bootstrap(modules: Record<string, ApiRequestDataTypeInterface>): void {\n Object.values(modules).forEach((module) => {\n if (module && module.model) {\n this.registerObjectClass(module, module.model);\n }\n });\n }\n\n /**\n * Clear all registered classes. Useful for testing.\n */\n public static clear(): void {\n this._map.clear();\n }\n}\n\n// Export alias for backward compatibility\nexport { DataClassRegistry as DataClass };\n","import { ApiDataInterface } from \"../interfaces/ApiDataInterface\";\nimport { ApiRequestDataTypeInterface } from \"../interfaces/ApiRequestDataTypeInterface\";\nimport { DataClassRegistry } from \"../registry/DataClassRegistry\";\n\nexport class JsonApiDataFactory {\n public static create(classKey: ApiRequestDataTypeInterface, data: any): any {\n const factoryClass = DataClassRegistry.get(classKey);\n\n const instance = new factoryClass() as ApiDataInterface;\n const result = instance.createJsonApi(data);\n return result;\n }\n}\n","/**\n * Centralized bootstrap store accessible from ModuleRegistry.\n * This file has NO external dependencies to avoid circular imports.\n *\n * The bootstrap store allows ModuleRegistry to call the app's bootstrapper\n * when modules are accessed before bootstrap() was called, providing\n * self-healing behavior for module evaluation order issues.\n *\n * IMPORTANT: We use globalThis to persist state across HMR/Turbopack\n * module re-evaluations in development mode. Without this, the bootstrapper\n * reference would be lost when modules are hot-reloaded, causing\n * \"Module not registered\" errors during navigation.\n */\n\ntype BootstrapperFn = () => void;\n\n// Symbol key to avoid conflicts with other globals\nconst BOOTSTRAP_KEY = Symbol.for(\"nextjs-jsonapi:bootstrapper\");\nconst BOOTSTRAP_ATTEMPTED_KEY = Symbol.for(\"nextjs-jsonapi:bootstrapAttempted\");\n\n// Use globalThis to persist across HMR reloads\nconst globalStore = globalThis as unknown as {\n [BOOTSTRAP_KEY]?: BootstrapperFn | null;\n [BOOTSTRAP_ATTEMPTED_KEY]?: boolean;\n};\n\n// Initialize from global if not set\nif (globalStore[BOOTSTRAP_KEY] === undefined) {\n globalStore[BOOTSTRAP_KEY] = null;\n}\nif (globalStore[BOOTSTRAP_ATTEMPTED_KEY] === undefined) {\n globalStore[BOOTSTRAP_ATTEMPTED_KEY] = false;\n}\n\n// Getters/setters that use the global store\nfunction getBootstrapperInternal(): BootstrapperFn | null {\n return globalStore[BOOTSTRAP_KEY] ?? null;\n}\n\nfunction setBootstrapperInternal(fn: BootstrapperFn | null): void {\n globalStore[BOOTSTRAP_KEY] = fn;\n}\n\nfunction getBootstrapAttempted(): boolean {\n return globalStore[BOOTSTRAP_ATTEMPTED_KEY] ?? false;\n}\n\nfunction setBootstrapAttempted(value: boolean): void {\n globalStore[BOOTSTRAP_ATTEMPTED_KEY] = value;\n}\n\n/**\n * Register the bootstrapper function.\n * Called by configureJsonApi() from client/config, client/JsonApiClient, or unified/JsonApiRequest.\n */\nexport function setBootstrapper(fn: BootstrapperFn): void {\n setBootstrapperInternal(fn);\n}\n\n/**\n * Get the registered bootstrapper function.\n * Returns null if no bootstrapper has been registered.\n */\nexport function getBootstrapper(): BootstrapperFn | null {\n return getBootstrapperInternal();\n}\n\n/**\n * Attempt to run the bootstrapper if one is registered.\n * Returns true if bootstrapper was executed, false if not available.\n * Safe to call multiple times - bootstrapper is expected to be idempotent.\n */\nexport function tryBootstrap(): boolean {\n const bootstrapper = getBootstrapperInternal();\n const attempted = getBootstrapAttempted();\n\n if (attempted && !bootstrapper) {\n // Already tried and no bootstrapper available\n return false;\n }\n setBootstrapAttempted(true);\n\n if (bootstrapper) {\n bootstrapper();\n return true;\n }\n return false;\n}\n\n/**\n * Check if a bootstrapper has been registered.\n */\nexport function hasBootstrapper(): boolean {\n return getBootstrapperInternal() !== null;\n}\n\n/**\n * Reset the bootstrap store. Useful for testing.\n */\nexport function resetBootstrapStore(): void {\n setBootstrapperInternal(null);\n setBootstrapAttempted(false);\n}\n","import { ApiData } from \"../interfaces/ApiData\";\nimport { ApiDataInterface } from \"../interfaces/ApiDataInterface\";\nimport { ApiRequestDataTypeInterface } from \"../interfaces/ApiRequestDataTypeInterface\";\nimport { ApiResponseInterface } from \"../interfaces/ApiResponseInterface\";\nimport { DataClassRegistry } from \"../registry/DataClassRegistry\";\n\n/**\n * Translates raw JSON:API data into typed objects.\n * Does not require API response metadata.\n */\nexport function translateData<T extends ApiDataInterface>(params: {\n classKey: ApiRequestDataTypeInterface;\n data: any;\n}): T | T[] {\n const factoryClass = DataClassRegistry.get(params.classKey);\n\n if (!factoryClass) {\n throw new Error(\n `Class not registered for key: ${typeof params.classKey === \"string\" ? params.classKey : params.classKey.name}`,\n );\n }\n\n const included: any = params.data.included ?? [];\n\n if (Array.isArray(params.data.data)) {\n const responseData: T[] = [];\n\n for (const data of params.data.data) {\n const object = new factoryClass();\n object.rehydrate({ jsonApi: data, included: included, allData: params.data.data });\n responseData.push(object as T);\n }\n\n return responseData as T[];\n } else {\n const responseData = new factoryClass();\n responseData.rehydrate({\n jsonApi: params.data.data,\n included: included,\n });\n\n return responseData as T;\n }\n}\n\n/**\n * Translates a full API response into a typed ApiResponseInterface.\n * Includes pagination support.\n */\nexport async function translateResponse<T extends ApiDataInterface>(params: {\n classKey: ApiRequestDataTypeInterface;\n apiResponse: ApiData;\n companyId?: string;\n language: string;\n paginationHandler?: (endpoint: string) => Promise<ApiResponseInterface>;\n}): Promise<ApiResponseInterface> {\n const response: ApiResponseInterface = {\n ok: true,\n response: 0,\n data: [],\n error: \"\",\n };\n\n const factoryClass = DataClassRegistry.get(params.classKey);\n\n if (!factoryClass) {\n throw new Error(\n `Class not registered for key: ${typeof params.classKey === \"string\" ? params.classKey : params.classKey.name}`,\n );\n }\n\n response.ok = params.apiResponse.ok;\n response.response = params.apiResponse.status;\n\n if (!params.apiResponse.ok) {\n // The nestjs-neo4jsonapi `HttpExceptionFilter` emits a JSON:API error document\n // (`errors: [{ status, title, detail, ... }]`), so `detail` is read first, then the legacy\n // `message`/`error` keys, then `statusText` (empty over HTTP/2).\n response.error =\n params.apiResponse?.data?.errors?.[0]?.detail ??\n params.apiResponse?.data?.message ??\n params.apiResponse?.data?.error ??\n params.apiResponse.statusText;\n response.raw = params.apiResponse.data;\n return response;\n }\n\n if (params.apiResponse.status === 204) return response;\n\n // A success with no body (e.g. a 200 from a handler that sends nothing —\n // @HttpCode is inert when a controller injects @Res, so \"204\" endpoints can\n // arrive as empty 200s) translates to an empty success, not a crash on\n // `.included` below.\n if (params.apiResponse.data === undefined || params.apiResponse.data === null) return response;\n\n response.raw = params.apiResponse.data;\n\n // Extract meta from JSON:API response\n if (params.apiResponse.data?.meta) {\n response.meta = params.apiResponse.data.meta;\n }\n\n try {\n // Check if response is JSON:API formatted (has a 'data' property)\n // If not, return the raw response data directly (e.g., { url: \"...\" } or { clientSecret: \"...\" })\n if (\n params.apiResponse.data &&\n typeof params.apiResponse.data === \"object\" &&\n !Array.isArray(params.apiResponse.data) &&\n params.apiResponse.data.data === undefined\n ) {\n response.data = params.apiResponse.data;\n return response;\n }\n\n const included: any = params.apiResponse.data.included ?? [];\n\n if (params.apiResponse.data.links) {\n response.self = params.apiResponse.data.links.self;\n\n if (params.apiResponse.data.links.next && params.paginationHandler) {\n response.next = params.apiResponse.data.links.next;\n response.nextPage = async () => params.paginationHandler!(params.apiResponse.data.links.next);\n }\n\n if (params.apiResponse.data.links.prev && params.paginationHandler) {\n response.prev = params.apiResponse.data.links.prev;\n response.prevPage = async () => params.paginationHandler!(params.apiResponse.data.links.prev);\n }\n }\n\n if (Array.isArray(params.apiResponse.data.data)) {\n const responseData: T[] = [];\n\n for (const data of params.apiResponse.data.data) {\n const object = new factoryClass();\n object.rehydrate({ jsonApi: data, included: included, allData: params.apiResponse.data.data });\n responseData.push(object as T);\n }\n\n response.data = responseData;\n } else {\n const responseData = new factoryClass();\n responseData.rehydrate({\n jsonApi: params.apiResponse.data.data,\n included: included,\n });\n\n response.data = responseData;\n }\n } catch (e) {\n console.error(e);\n }\n\n return response;\n}\n","import { ENV } from \"../core/env\";\nimport { JsonApiDataFactory } from \"../core/factories/JsonApiDataFactory\";\nimport { ApiData } from \"../core/interfaces/ApiData\";\nimport { ApiRequestDataTypeInterface } from \"../core/interfaces/ApiRequestDataTypeInterface\";\nimport { ApiResponseInterface } from \"../core/interfaces/ApiResponseInterface\";\nimport { setBootstrapper } from \"../core/registry/bootstrapStore\";\nimport { translateResponse } from \"../core/utils/translateResponse\";\nimport { ModuleWithPermissions } from \"../permissions/types\";\n\n// Type definitions for dynamically imported functions (avoiding typeof import to prevent bundling)\ntype DirectFetchFn = (params: {\n method: string;\n url: string;\n token?: string;\n body?: any;\n files?: { [key: string]: File | Blob } | File | Blob;\n companyId?: string;\n language: string;\n additionalHeaders?: Record<string, string>;\n credentials?: RequestCredentials;\n}) => Promise<ApiData>;\n\ntype ServerRequestFn = (params: {\n method: string;\n url: string;\n token?: string;\n cache?: string;\n body?: any;\n files?: { [key: string]: File | Blob } | File | Blob;\n companyId?: string;\n language: string;\n additionalHeaders?: Record<string, string>;\n}) => Promise<ApiData>;\n\ntype GetTokenFn = () => Promise<string | undefined>;\n\n// These will be dynamically imported based on environment\nlet _directFetch: DirectFetchFn;\nlet _serverRequest: ServerRequestFn;\nlet _getClientToken: GetTokenFn;\nlet _getServerToken: GetTokenFn;\n\n// Config storage for non-React contexts\nlet _staticConfig: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n bootstrapper?: () => void;\n additionalHeaders?: Record<string, string>;\n} | null = null;\n\n/**\n * Configure the JSON:API client for non-React contexts (e.g., server components).\n * For React contexts, use JsonApiProvider instead.\n */\nexport function configureJsonApi(config: {\n apiUrl: string;\n appUrl?: string;\n trackablePages?: ModuleWithPermissions[];\n bootstrapper?: () => void;\n additionalHeaders?: Record<string, string>;\n}): void {\n _staticConfig = config;\n // Register and call bootstrapper to register all modules\n if (config.bootstrapper) {\n setBootstrapper(config.bootstrapper);\n config.bootstrapper();\n }\n}\n\nasync function getToken(): Promise<string | undefined> {\n if (typeof window === \"undefined\") {\n // Server-side\n if (!_getServerToken) {\n const serverModule = await import(\"../server/token\");\n _getServerToken = serverModule.getServerToken;\n }\n return _getServerToken();\n } else {\n // Client-side\n if (!_getClientToken) {\n const clientModule = await import(\"../client/token\");\n _getClientToken = clientModule.getClientToken;\n }\n return _getClientToken();\n }\n}\n\nasync function makeRequest(params: {\n method: string;\n url: string;\n token?: string;\n cache?: string;\n body?: any;\n files?: { [key: string]: File | Blob } | File | Blob;\n companyId?: string;\n language: string;\n additionalHeaders?: Record<string, string>;\n /** Client-side only: forwarded to the browser `fetch`. Ignored on the server. */\n credentials?: RequestCredentials;\n}): Promise<ApiData> {\n if (typeof window !== \"undefined\") {\n // Client-side: use direct fetch\n if (!_directFetch) {\n const clientModule = await import(\"../client/request\");\n _directFetch = clientModule.directFetch;\n }\n return _directFetch({\n method: params.method,\n url: params.url,\n token: params.token,\n body: params.body,\n files: params.files,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: params.additionalHeaders,\n credentials: params.credentials,\n });\n } else {\n // Server-side: use server request with caching\n if (!_serverRequest) {\n const serverModule = await import(\"../server/request\");\n _serverRequest = serverModule.serverRequest;\n }\n return _serverRequest({\n method: params.method,\n url: params.url,\n token: params.token,\n cache: params.cache,\n body: params.body,\n files: params.files,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: params.additionalHeaders,\n });\n }\n}\n\nexport function getApiUrl(): string {\n if (_staticConfig?.apiUrl) {\n return _staticConfig.apiUrl;\n }\n // Fallback to environment variable\n const envUrl = ENV.API_URL;\n if (!envUrl) {\n throw new Error(\"API URL not configured. Use configureJsonApi() or set NEXT_PUBLIC_API_URL environment variable.\");\n }\n return envUrl;\n}\n\nexport function getAppUrl(): string {\n if (_staticConfig?.appUrl) {\n return _staticConfig.appUrl;\n }\n // Fallback to environment variable\n const envUrl = ENV.APP_URL;\n if (!envUrl) {\n throw new Error(\n \"App URL not configured. Use configureJsonApi({ appUrl }) or set NEXT_PUBLIC_ADDRESS environment variable.\",\n );\n }\n return envUrl.trim().replace(/\\/+$/, \"\");\n}\n\nexport function getTrackablePages(): ModuleWithPermissions[] {\n return _staticConfig?.trackablePages ?? [];\n}\n\nfunction runBootstrapper(): void {\n if (_staticConfig?.bootstrapper) {\n _staticConfig.bootstrapper();\n }\n}\n\n/**\n * Resolve the final request URL for an endpoint.\n *\n * - `endpoint` starting with \"http\" is always passed through unchanged (existing behaviour).\n * - Otherwise, an explicit `baseUrl` (per-call override) takes precedence over the global\n * `getApiUrl()` resolution. Omitting `baseUrl` preserves today's behaviour exactly.\n */\nexport function buildUrl(endpoint: string, baseUrl?: string): string {\n if (endpoint.startsWith(\"http\")) return endpoint;\n const apiUrl = baseUrl ?? getApiUrl();\n return `${apiUrl}${endpoint}`;\n}\n\nexport async function JsonApiGet(params: {\n classKey: ApiRequestDataTypeInterface;\n endpoint: string;\n companyId?: string;\n language: string;\n token?: string;\n baseUrl?: string;\n credentials?: RequestCredentials;\n}): Promise<ApiResponseInterface> {\n runBootstrapper();\n // A cached server GET never sends the token, so it must not read the cookie either:\n // the read would make a public page dynamic.\n const isServerCached = typeof window === \"undefined\" && !!params.classKey.cache;\n const token = isServerCached ? undefined : (params.token ?? (await getToken()));\n\n const apiResponse = await makeRequest({\n method: \"GET\",\n url: buildUrl(params.endpoint, params.baseUrl),\n token,\n cache: params.classKey.cache,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: _staticConfig?.additionalHeaders,\n credentials: params.credentials,\n });\n\n return translateResponse({\n classKey: params.classKey,\n apiResponse,\n companyId: params.companyId,\n language: params.language,\n paginationHandler: async (endpoint: string) =>\n JsonApiGet({\n classKey: params.classKey,\n endpoint,\n companyId: params.companyId,\n language: params.language,\n token: params.token,\n baseUrl: params.baseUrl,\n }),\n });\n}\n\nexport async function JsonApiPost(params: {\n classKey: ApiRequestDataTypeInterface;\n endpoint: string;\n companyId?: string;\n body?: any;\n overridesJsonApiCreation?: boolean;\n files?: { [key: string]: File | Blob } | File | Blob;\n language: string;\n responseType?: ApiRequestDataTypeInterface;\n token?: string;\n baseUrl?: string;\n credentials?: RequestCredentials;\n}): Promise<ApiResponseInterface> {\n runBootstrapper();\n const token = params.token ?? (await getToken());\n\n let body = params.body;\n if (!body) {\n body = {};\n } else if (params.overridesJsonApiCreation !== true) {\n body = JsonApiDataFactory.create(params.classKey, body);\n }\n\n const apiResponse = await makeRequest({\n method: \"POST\",\n url: buildUrl(params.endpoint, params.baseUrl),\n token,\n body,\n files: params.files,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: _staticConfig?.additionalHeaders,\n credentials: params.credentials,\n });\n\n return translateResponse({\n classKey: params.responseType ?? params.classKey,\n apiResponse,\n companyId: params.companyId,\n language: params.language,\n });\n}\n\nexport async function JsonApiPut(params: {\n classKey: ApiRequestDataTypeInterface;\n endpoint: string;\n companyId?: string;\n body?: any;\n files?: { [key: string]: File | Blob } | File | Blob;\n language: string;\n responseType?: ApiRequestDataTypeInterface;\n token?: string;\n baseUrl?: string;\n credentials?: RequestCredentials;\n}): Promise<ApiResponseInterface> {\n runBootstrapper();\n const token = params.token ?? (await getToken());\n\n let body = params.body;\n if (!body) {\n body = {};\n } else {\n body = JsonApiDataFactory.create(params.classKey, body);\n }\n\n const apiResponse = await makeRequest({\n method: \"PUT\",\n url: buildUrl(params.endpoint, params.baseUrl),\n token,\n body,\n files: params.files,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: _staticConfig?.additionalHeaders,\n credentials: params.credentials,\n });\n\n return translateResponse({\n classKey: params.responseType ?? params.classKey,\n apiResponse,\n companyId: params.companyId,\n language: params.language,\n });\n}\n\nexport async function JsonApiPatch(params: {\n classKey: ApiRequestDataTypeInterface;\n endpoint: string;\n companyId?: string;\n body?: any;\n files?: { [key: string]: File | Blob } | File | Blob;\n overridesJsonApiCreation?: boolean;\n responseType?: ApiRequestDataTypeInterface;\n language: string;\n token?: string;\n baseUrl?: string;\n credentials?: RequestCredentials;\n}): Promise<ApiResponseInterface> {\n runBootstrapper();\n const token = params.token ?? (await getToken());\n\n let body = params.body;\n if (!body) {\n body = {};\n } else if (params.overridesJsonApiCreation !== true) {\n body = JsonApiDataFactory.create(params.classKey, body);\n }\n\n const apiResponse = await makeRequest({\n method: \"PATCH\",\n url: buildUrl(params.endpoint, params.baseUrl),\n token,\n body,\n files: params.files,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: _staticConfig?.additionalHeaders,\n credentials: params.credentials,\n });\n\n return translateResponse({\n classKey: params.responseType ?? params.classKey,\n apiResponse,\n companyId: params.companyId,\n language: params.language,\n });\n}\n\nexport async function JsonApiDelete(params: {\n classKey: ApiRequestDataTypeInterface;\n endpoint: string;\n companyId?: string;\n language: string;\n responseType?: ApiRequestDataTypeInterface;\n token?: string;\n baseUrl?: string;\n credentials?: RequestCredentials;\n}): Promise<ApiResponseInterface> {\n runBootstrapper();\n const token = params.token ?? (await getToken());\n\n const apiResponse = await makeRequest({\n method: \"DELETE\",\n url: buildUrl(params.endpoint, params.baseUrl),\n token,\n companyId: params.companyId,\n language: params.language,\n additionalHeaders: _staticConfig?.additionalHeaders,\n credentials: params.credentials,\n });\n\n return translateResponse({\n classKey: params.responseType ?? params.classKey,\n apiResponse,\n companyId: params.companyId,\n language: params.language,\n });\n}\n"],"mappings":"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","names":[]}
@@ -10,7 +10,7 @@ var _chunk6RCZ64BQjs = require('./chunk-6RCZ64BQ.js');
10
10
 
11
11
 
12
12
 
13
- var _chunkN5ZE2Z6Ijs = require('./chunk-N5ZE2Z6I.js');
13
+ var _chunk53SD4YRFjs = require('./chunk-53SD4YRF.js');
14
14
 
15
15
 
16
16
 
@@ -115,9 +115,9 @@ async function updateLinks(store, typeConfig, record, before, after) {
115
115
  if (!relationship || !("data" in relationship)) continue;
116
116
  const next = new Map(identifiersOf(relationship).map((identifier) => [identifier.id, identifier]));
117
117
  const previous = new Set(identifiersOf(_optionalChain([before, 'optionalAccess', _6 => _6[name]])).map((identifier) => identifier.id));
118
- const kinds = _nullishCoalesce(_chunkN5ZE2Z6Ijs.linkKindsOf.call(void 0, typeConfig, name), () => ( [name]));
119
- const ofRelationship = await _chunkN5ZE2Z6Ijs.linksOfKind.call(void 0, store, record.id, kinds, "both");
120
- const mapped = _chunkN5ZE2Z6Ijs.linkKindsOf.call(void 0, typeConfig, name) !== void 0;
118
+ const kinds = _nullishCoalesce(_chunk53SD4YRFjs.linkKindsOf.call(void 0, typeConfig, name), () => ( [name]));
119
+ const ofRelationship = await _chunk53SD4YRFjs.linksOfKind.call(void 0, store, record.id, kinds, "both");
120
+ const mapped = _chunk53SD4YRFjs.linkKindsOf.call(void 0, typeConfig, name) !== void 0;
121
121
  const stale = [
122
122
  ...ofRelationship.filter((link) => !next.has(otherEnd(link))),
123
123
  // Unmapped: the link to an identifier the record held before may carry any kind.
@@ -125,7 +125,7 @@ async function updateLinks(store, typeConfig, record, before, after) {
125
125
  ];
126
126
  for (const link of stale) await store.deleteLink({ fromId: link.fromId, toId: link.toId, kind: link.kind });
127
127
  const linked = new Set(
128
- (mapped ? await _chunkN5ZE2Z6Ijs.linksOfKind.call(void 0, store, record.id, kinds, "both") : await allLinks()).map(otherEnd)
128
+ (mapped ? await _chunk53SD4YRFjs.linksOfKind.call(void 0, store, record.id, kinds, "both") : await allLinks()).map(otherEnd)
129
129
  );
130
130
  for (const [id, identifier] of next) {
131
131
  if (linked.has(id)) continue;
@@ -134,7 +134,7 @@ async function updateLinks(store, typeConfig, record, before, after) {
134
134
  fromId: record.id,
135
135
  toType: identifier.type,
136
136
  toId: id,
137
- kind: _chunkN5ZE2Z6Ijs.linkKindFor.call(void 0, typeConfig, name),
137
+ kind: _chunk53SD4YRFjs.linkKindFor.call(void 0, typeConfig, name),
138
138
  props: {}
139
139
  });
140
140
  }
@@ -148,7 +148,7 @@ async function storeResource(store, resource, pathRootId, waiting, kept, primary
148
148
  if (waiting.has(recordKeyOf(resource.type, resource.id))) return;
149
149
  const existing = await store.getRecord(resource.type, resource.id);
150
150
  if (existing && existing.base !== null) return;
151
- const rootId = await _asyncNullishCoalesce(await _asyncNullishCoalesce(await _asyncOptionalChain([existing, 'optionalAccess', async _9 => _9.rootId]), async () => ( await _chunkN5ZE2Z6Ijs.rootIdForResource.call(void 0, store, config, resource))), async () => ( pathRootId));
151
+ const rootId = await _asyncNullishCoalesce(await _asyncNullishCoalesce(await _asyncOptionalChain([existing, 'optionalAccess', async _9 => _9.rootId]), async () => ( await _chunk53SD4YRFjs.rootIdForResource.call(void 0, store, config, resource))), async () => ( pathRootId));
152
152
  if (!rootId) return;
153
153
  if (!kept.has(rootId)) return;
154
154
  const before = _nullishCoalesce(_optionalChain([existing, 'optionalAccess', _10 => _10.resource]), () => ( {}));
@@ -182,11 +182,11 @@ async function writeThrough(request, response) {
182
182
  try {
183
183
  const config = _chunkWUNSG3INjs.getOfflineConfig.call(void 0, );
184
184
  if (!config.getUserId()) return;
185
- const { path } = _chunkN5ZE2Z6Ijs.splitApiUrl.call(void 0, request.url);
185
+ const { path } = _chunk53SD4YRFjs.splitApiUrl.call(void 0, request.url);
186
186
  const store = await _chunkWUNSG3INjs.getOfflineStore.call(void 0, );
187
187
  if (method === "DELETE") {
188
188
  for (const typeConfig of config.types) {
189
- const params = _chunkN5ZE2Z6Ijs.matchPattern.call(void 0, [typeConfig.module, ":id"], path);
189
+ const params = _chunk53SD4YRFjs.matchPattern.call(void 0, [typeConfig.module, ":id"], path);
190
190
  if (params) {
191
191
  await store.deleteRecord(typeConfig.module.name, params.id);
192
192
  return;
@@ -195,7 +195,7 @@ async function writeThrough(request, response) {
195
195
  return;
196
196
  }
197
197
  const rootSegments = path.split("/").slice(0, 2).join("/");
198
- const pathRootId = _chunkWUNSG3INjs.rootKinds.call(void 0, config).map((kind) => _optionalChain([_chunkN5ZE2Z6Ijs.matchPattern.call(void 0, [kind.module, ":rootId"], rootSegments), 'optionalAccess', _13 => _13.rootId])).find((rootId) => rootId !== void 0);
198
+ const pathRootId = _chunkWUNSG3INjs.rootKinds.call(void 0, config).map((kind) => _optionalChain([_chunk53SD4YRFjs.matchPattern.call(void 0, [kind.module, ":rootId"], rootSegments), 'optionalAccess', _13 => _13.rootId])).find((rootId) => rootId !== void 0);
199
199
  const document = response.data;
200
200
  const primary = Array.isArray(_optionalChain([document, 'optionalAccess', _14 => _14.data])) ? document.data : _optionalChain([document, 'optionalAccess', _15 => _15.data]) ? [document.data] : [];
201
201
  const waiting = waitingRecordKeys(
@@ -230,4 +230,4 @@ _chunk7QVYU63Ejs.__name.call(void 0, writeThrough, "writeThrough");
230
230
 
231
231
 
232
232
  exports.rememberSyncRoots = rememberSyncRoots; exports.knownRootIds = knownRootIds; exports.knownPrimaryRootIds = knownPrimaryRootIds; exports.refreshLockedRoots = refreshLockedRoots; exports.recordKeyOf = recordKeyOf; exports.recordKeysOfEntry = recordKeysOfEntry; exports.waitingRecordKeys = waitingRecordKeys; exports.writeThrough = writeThrough;
233
- //# sourceMappingURL=chunk-QGVVF77L.js.map
233
+ //# sourceMappingURL=chunk-YSE2Z4RB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-QGVVF77L.js","../src/offline/sync/known-roots.ts","../src/offline/sync/waiting.ts","../src/offline/write-through.ts"],"names":[],"mappings":"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","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-QGVVF77L.js","sourcesContent":[null,"import { getOfflineConfig, getOfflineStore, rootKinds } from \"../config\";\nimport { setOfflineState } from \"../state\";\nimport type { DeviceStore } from \"../store/DeviceStore\";\nimport { isRootLocked } from \"../store/lifecycle\";\n\nlet _lastSyncRoots: string[] = [];\nlet _lastExtraSyncRoots: string[] = [];\n\n/**\n * Remembers the root records the last online sync listed: `ids` of every kind, `extraIds` those\n * of the `extraRootKinds` among them.\n */\nexport function rememberSyncRoots(ids: string[], extraIds: string[] = []): void {\n _lastSyncRoots = [...ids];\n _lastExtraSyncRoots = [...extraIds];\n}\n\n/**\n * Every root record the device knows of, of every kind: its stored root records, the root records\n * with waiting changes, and the last sync roots (a locked root record is never downloaded, so it\n * may have no stored record).\n */\nexport async function knownRootIds(store: DeviceStore): Promise<string[]> {\n const config = getOfflineConfig();\n const ids = new Set<string>(_lastSyncRoots);\n for (const kind of rootKinds(config)) {\n for (const record of await store.listRecords({ type: kind.module.name })) ids.add(record.id);\n }\n for (const entry of await store.queue()) ids.add(entry.rootId);\n return [...ids].sort();\n}\n\n/** The known root records of the `extraRootKinds`: stored, or listed by the last sync. */\nasync function extraRootIds(store: DeviceStore): Promise<Set<string>> {\n const ids = new Set<string>(_lastExtraSyncRoots);\n for (const kind of getOfflineConfig().extraRootKinds ?? []) {\n for (const record of await store.listRecords({ type: kind.module.name })) ids.add(record.id);\n }\n return ids;\n}\n\n/** `knownRootIds` without the root records of the `extraRootKinds` (the primary kind only). */\nexport async function knownPrimaryRootIds(store: DeviceStore): Promise<string[]> {\n const extra = await extraRootIds(store);\n return (await knownRootIds(store)).filter((id) => !extra.has(id));\n}\n\n/** Recomputes `lockedRootIds` from the stored sync states, now. */\nexport async function refreshLockedRoots(): Promise<void> {\n const config = getOfflineConfig();\n if (!config.getUserId()) return;\n const store = await getOfflineStore();\n const now = new Date();\n const locked: string[] = [];\n for (const id of await knownRootIds(store)) {\n if (isRootLocked(await store.getSyncState(id), now)) locked.push(id);\n }\n setOfflineState({ lockedRootIds: locked });\n}\n","import type { QueueEntry } from \"../store/DeviceStore\";\n\nexport const recordKeyOf = (type: string, id: string) => `${type}:${id}`;\n\n/**\n * The records a queue entry targets: its `recordType`/`recordId`, the `data.type`/`data.id` of\n * its body (a record created on this device), and the `<type>/<id>` of its path (the last\n * segment naming a synced type, when an id follows it: `npcs/n1`, `npcs/n1/merge`; a collection\n * path such as `roots/C/npcs` targets no record).\n */\nexport function recordKeysOfEntry(entry: QueueEntry, typeNames: Set<string>): string[] {\n const keys: string[] = [];\n if (entry.recordType && entry.recordId) keys.push(recordKeyOf(entry.recordType, entry.recordId));\n\n const data = entry.body?.data;\n if (data && !Array.isArray(data) && typeof data.type === \"string\" && typeof data.id === \"string\") {\n keys.push(recordKeyOf(data.type, data.id));\n }\n\n const segments = String(entry.path ?? \"\")\n .split(\"?\")[0]\n .split(\"/\")\n .filter(Boolean);\n for (let index = segments.length - 1; index >= 0; index--) {\n if (!typeNames.has(segments[index])) continue;\n if (index + 1 < segments.length) keys.push(recordKeyOf(segments[index], segments[index + 1]));\n break;\n }\n return keys;\n}\n\n/**\n * Every record with a waiting change: targeted by a queue entry that is pending, sending, in\n * conflict or failed. Such a record is never overwritten or deleted by a sync or a write-through.\n */\nexport function waitingRecordKeys(queue: QueueEntry[], typeNames: Set<string>): Set<string> {\n const keys = new Set<string>();\n for (const entry of queue) for (const key of recordKeysOfEntry(entry, typeNames)) keys.add(key);\n return keys;\n}\n","import type { ApiData } from \"../core/interfaces/ApiData\";\nimport { getOfflineConfig, getOfflineStore, OfflineUnavailableError, rootKinds } from \"./config\";\nimport { rootIdForResource, linkKindFor, linkKindsOf, linksOfKind } from \"./generic-answers\";\nimport { splitApiUrl } from \"./local-transport\";\nimport { matchPattern } from \"./router\";\nimport type { DeviceStore, StoredLink } from \"./store/DeviceStore\";\nimport type { OfflineTypeConfig } from \"./types\";\nimport { cacheArtworkImage, imageUrlOf } from \"./sync/artwork-cache\";\nimport { knownRootIds } from \"./sync/known-roots\";\nimport { recordKeyOf, waitingRecordKeys } from \"./sync/waiting\";\n\nexport type WriteThroughRequest = { method: string; url: string };\n\nfunction updatedAtOf(resource: any): Date | null {\n const value = resource?.attributes?.updatedAt;\n if (!value) return null;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\ntype Identifier = { type: string; id: string };\n\nfunction identifiersOf(relationship: any): Identifier[] {\n const data = relationship?.data;\n if (!data) return [];\n return (Array.isArray(data) ? data : [data]).filter((item: any) => item && item.type && item.id);\n}\n\n/**\n * Brings the stored links of the written record in line with the relationships the answer\n * carries (only those whose `data` it holds), as the local answers do: a link of the\n * relationship (its name or mapped Neo4j type; any kind when the type is not mapped, for an\n * identifier the record held before) to an identifier no longer there is removed, and a new\n * identifier gets a link of `linkKindFor` the relationship.\n */\nasync function updateLinks(\n store: DeviceStore,\n typeConfig: OfflineTypeConfig | undefined,\n record: Identifier,\n before: any,\n after: any,\n): Promise<void> {\n const otherEnd = (link: StoredLink) => (link.fromId === record.id ? link.toId : link.fromId);\n const allLinks = async (): Promise<StoredLink[]> => [\n ...(await store.linksFrom(record.id)),\n ...(await store.linksTo(record.id)),\n ];\n\n for (const [name, relationship] of Object.entries<any>(after ?? {})) {\n if (!relationship || !(\"data\" in relationship)) continue;\n const next = new Map(identifiersOf(relationship).map((identifier) => [identifier.id, identifier]));\n const previous = new Set(identifiersOf(before?.[name]).map((identifier) => identifier.id));\n const kinds = linkKindsOf(typeConfig, name) ?? [name];\n const ofRelationship = await linksOfKind(store, record.id, kinds, \"both\");\n const mapped = linkKindsOf(typeConfig, name) !== undefined;\n\n const stale = [\n ...ofRelationship.filter((link) => !next.has(otherEnd(link))),\n // Unmapped: the link to an identifier the record held before may carry any kind.\n ...(mapped ? [] : (await allLinks()).filter((link) => previous.has(otherEnd(link)) && !next.has(otherEnd(link)))),\n ];\n for (const link of stale) await store.deleteLink({ fromId: link.fromId, toId: link.toId, kind: link.kind });\n\n const linked = new Set(\n (mapped ? await linksOfKind(store, record.id, kinds, \"both\") : await allLinks()).map(otherEnd),\n );\n for (const [id, identifier] of next) {\n if (linked.has(id)) continue;\n await store.putLink({\n fromType: record.type,\n fromId: record.id,\n toType: identifier.type,\n toId: id,\n kind: linkKindFor(typeConfig, name),\n props: {},\n });\n }\n }\n}\n\ntype ImageChange = { url: string; previousUrl?: string };\n\nasync function storeResource(\n store: DeviceStore,\n resource: any,\n pathRootId: string | undefined,\n waiting: Set<string>,\n kept: Set<string>,\n primary: boolean,\n images: ImageChange[],\n): Promise<void> {\n const config = getOfflineConfig();\n if (!resource?.type || !resource?.id) return;\n if (!config.types.some((typeConfig) => typeConfig.module.name === resource.type)) return;\n // A record with unsent local changes keeps them: the next sync, once they are sent, brings\n // the server's version.\n if (waiting.has(recordKeyOf(resource.type, resource.id))) return;\n\n const existing = await store.getRecord(resource.type, resource.id);\n if (existing && existing.base !== null) return;\n const rootId = existing?.rootId ?? (await rootIdForResource(store, config, resource)) ?? pathRootId;\n // A record that belongs to no root record on this device waits for the next sync.\n if (!rootId) return;\n // Only the root records the device keeps are written through (never a player's root record).\n if (!kept.has(rootId)) return;\n\n // An answer can carry a sparse resource (fields limited): it is merged onto what is stored.\n const before = existing?.resource ?? {};\n const merged = {\n ...before,\n ...resource,\n attributes: { ...(before.attributes ?? {}), ...(resource.attributes ?? {}) },\n relationships: { ...(before.relationships ?? {}), ...(resource.relationships ?? {}) },\n };\n\n await store.putRecord({\n type: resource.type,\n id: resource.id,\n rootId,\n resource: merged,\n updatedAt: updatedAtOf(resource) ?? existing?.updatedAt ?? null,\n base: null,\n localOnly: false,\n });\n if (primary) {\n const typeConfig = config.types.find((candidate) => candidate.module.name === resource.type);\n await updateLinks(store, typeConfig, resource, before.relationships, resource.relationships);\n }\n\n const url = imageUrlOf(merged);\n const previousUrl = imageUrlOf(existing?.resource);\n if (url && url !== previousUrl) images.push({ url, previousUrl });\n}\n\n/**\n * After a successful online write, copies the answer into the device copy so it is never behind\n * the GM's own work: the resource and its `included` for POST/PUT/PATCH, the record removed for a\n * DELETE. It never fails the request: a problem is logged and the next sync repairs the copy.\n */\nexport async function writeThrough(request: WriteThroughRequest, response: ApiData): Promise<void> {\n const method = request.method.toUpperCase();\n if (method === \"GET\" || !response.ok) return;\n\n try {\n const config = getOfflineConfig();\n if (!config.getUserId()) return;\n const { path } = splitApiUrl(request.url);\n const store = await getOfflineStore();\n\n if (method === \"DELETE\") {\n for (const typeConfig of config.types) {\n const params = matchPattern([typeConfig.module, \":id\"], path);\n if (params) {\n await store.deleteRecord(typeConfig.module.name, params.id);\n return;\n }\n }\n return;\n }\n\n // A path under a root record of any kind (`<root module>/:rootId/...`).\n const rootSegments = path.split(\"/\").slice(0, 2).join(\"/\");\n const pathRootId = rootKinds(config)\n .map((kind) => matchPattern([kind.module, \":rootId\"], rootSegments)?.rootId)\n .find((rootId) => rootId !== undefined);\n\n const document = response.data;\n const primary = Array.isArray(document?.data) ? document.data : document?.data ? [document.data] : [];\n const waiting = waitingRecordKeys(\n await store.queue(),\n new Set(config.types.map((typeConfig) => typeConfig.module.name)),\n );\n // The root records this device keeps for the signed-in user (stored roots, waiting changes, last\n // sync roots): a write in any other root record (a player's) stores nothing.\n const kept = new Set(await knownRootIds(store));\n const images: ImageChange[] = [];\n await store.transaction(async (transactionStore) => {\n for (const resource of primary) {\n await storeResource(transactionStore, resource, pathRootId, waiting, kept, true, images);\n }\n for (const resource of document?.included ?? []) {\n await storeResource(transactionStore, resource, pathRootId, waiting, kept, false, images);\n }\n });\n // A new image URL of an artwork: downloaded, the old cached image removed (as the sync does).\n for (const image of images) await cacheArtworkImage(image.url, image.previousUrl);\n } catch (error) {\n // A browser that cannot keep the device copy was already warned about once.\n if (error instanceof OfflineUnavailableError) return;\n console.warn(\"[offline] could not copy the answer to the device\", error);\n }\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-YSE2Z4RB.js","../src/offline/sync/known-roots.ts","../src/offline/sync/waiting.ts","../src/offline/write-through.ts"],"names":[],"mappings":"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","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/chunk-YSE2Z4RB.js","sourcesContent":[null,"import { getOfflineConfig, getOfflineStore, rootKinds } from \"../config\";\nimport { setOfflineState } from \"../state\";\nimport type { DeviceStore } from \"../store/DeviceStore\";\nimport { isRootLocked } from \"../store/lifecycle\";\n\nlet _lastSyncRoots: string[] = [];\nlet _lastExtraSyncRoots: string[] = [];\n\n/**\n * Remembers the root records the last online sync listed: `ids` of every kind, `extraIds` those\n * of the `extraRootKinds` among them.\n */\nexport function rememberSyncRoots(ids: string[], extraIds: string[] = []): void {\n _lastSyncRoots = [...ids];\n _lastExtraSyncRoots = [...extraIds];\n}\n\n/**\n * Every root record the device knows of, of every kind: its stored root records, the root records\n * with waiting changes, and the last sync roots (a locked root record is never downloaded, so it\n * may have no stored record).\n */\nexport async function knownRootIds(store: DeviceStore): Promise<string[]> {\n const config = getOfflineConfig();\n const ids = new Set<string>(_lastSyncRoots);\n for (const kind of rootKinds(config)) {\n for (const record of await store.listRecords({ type: kind.module.name })) ids.add(record.id);\n }\n for (const entry of await store.queue()) ids.add(entry.rootId);\n return [...ids].sort();\n}\n\n/** The known root records of the `extraRootKinds`: stored, or listed by the last sync. */\nasync function extraRootIds(store: DeviceStore): Promise<Set<string>> {\n const ids = new Set<string>(_lastExtraSyncRoots);\n for (const kind of getOfflineConfig().extraRootKinds ?? []) {\n for (const record of await store.listRecords({ type: kind.module.name })) ids.add(record.id);\n }\n return ids;\n}\n\n/** `knownRootIds` without the root records of the `extraRootKinds` (the primary kind only). */\nexport async function knownPrimaryRootIds(store: DeviceStore): Promise<string[]> {\n const extra = await extraRootIds(store);\n return (await knownRootIds(store)).filter((id) => !extra.has(id));\n}\n\n/** Recomputes `lockedRootIds` from the stored sync states, now. */\nexport async function refreshLockedRoots(): Promise<void> {\n const config = getOfflineConfig();\n if (!config.getUserId()) return;\n const store = await getOfflineStore();\n const now = new Date();\n const locked: string[] = [];\n for (const id of await knownRootIds(store)) {\n if (isRootLocked(await store.getSyncState(id), now)) locked.push(id);\n }\n setOfflineState({ lockedRootIds: locked });\n}\n","import type { QueueEntry } from \"../store/DeviceStore\";\n\nexport const recordKeyOf = (type: string, id: string) => `${type}:${id}`;\n\n/**\n * The records a queue entry targets: its `recordType`/`recordId`, the `data.type`/`data.id` of\n * its body (a record created on this device), and the `<type>/<id>` of its path (the last\n * segment naming a synced type, when an id follows it: `npcs/n1`, `npcs/n1/merge`; a collection\n * path such as `roots/C/npcs` targets no record).\n */\nexport function recordKeysOfEntry(entry: QueueEntry, typeNames: Set<string>): string[] {\n const keys: string[] = [];\n if (entry.recordType && entry.recordId) keys.push(recordKeyOf(entry.recordType, entry.recordId));\n\n const data = entry.body?.data;\n if (data && !Array.isArray(data) && typeof data.type === \"string\" && typeof data.id === \"string\") {\n keys.push(recordKeyOf(data.type, data.id));\n }\n\n const segments = String(entry.path ?? \"\")\n .split(\"?\")[0]\n .split(\"/\")\n .filter(Boolean);\n for (let index = segments.length - 1; index >= 0; index--) {\n if (!typeNames.has(segments[index])) continue;\n if (index + 1 < segments.length) keys.push(recordKeyOf(segments[index], segments[index + 1]));\n break;\n }\n return keys;\n}\n\n/**\n * Every record with a waiting change: targeted by a queue entry that is pending, sending, in\n * conflict or failed. Such a record is never overwritten or deleted by a sync or a write-through.\n */\nexport function waitingRecordKeys(queue: QueueEntry[], typeNames: Set<string>): Set<string> {\n const keys = new Set<string>();\n for (const entry of queue) for (const key of recordKeysOfEntry(entry, typeNames)) keys.add(key);\n return keys;\n}\n","import type { ApiData } from \"../core/interfaces/ApiData\";\nimport { getOfflineConfig, getOfflineStore, OfflineUnavailableError, rootKinds } from \"./config\";\nimport { rootIdForResource, linkKindFor, linkKindsOf, linksOfKind } from \"./generic-answers\";\nimport { splitApiUrl } from \"./local-transport\";\nimport { matchPattern } from \"./router\";\nimport type { DeviceStore, StoredLink } from \"./store/DeviceStore\";\nimport type { OfflineTypeConfig } from \"./types\";\nimport { cacheArtworkImage, imageUrlOf } from \"./sync/artwork-cache\";\nimport { knownRootIds } from \"./sync/known-roots\";\nimport { recordKeyOf, waitingRecordKeys } from \"./sync/waiting\";\n\nexport type WriteThroughRequest = { method: string; url: string };\n\nfunction updatedAtOf(resource: any): Date | null {\n const value = resource?.attributes?.updatedAt;\n if (!value) return null;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\ntype Identifier = { type: string; id: string };\n\nfunction identifiersOf(relationship: any): Identifier[] {\n const data = relationship?.data;\n if (!data) return [];\n return (Array.isArray(data) ? data : [data]).filter((item: any) => item && item.type && item.id);\n}\n\n/**\n * Brings the stored links of the written record in line with the relationships the answer\n * carries (only those whose `data` it holds), as the local answers do: a link of the\n * relationship (its name or mapped Neo4j type; any kind when the type is not mapped, for an\n * identifier the record held before) to an identifier no longer there is removed, and a new\n * identifier gets a link of `linkKindFor` the relationship.\n */\nasync function updateLinks(\n store: DeviceStore,\n typeConfig: OfflineTypeConfig | undefined,\n record: Identifier,\n before: any,\n after: any,\n): Promise<void> {\n const otherEnd = (link: StoredLink) => (link.fromId === record.id ? link.toId : link.fromId);\n const allLinks = async (): Promise<StoredLink[]> => [\n ...(await store.linksFrom(record.id)),\n ...(await store.linksTo(record.id)),\n ];\n\n for (const [name, relationship] of Object.entries<any>(after ?? {})) {\n if (!relationship || !(\"data\" in relationship)) continue;\n const next = new Map(identifiersOf(relationship).map((identifier) => [identifier.id, identifier]));\n const previous = new Set(identifiersOf(before?.[name]).map((identifier) => identifier.id));\n const kinds = linkKindsOf(typeConfig, name) ?? [name];\n const ofRelationship = await linksOfKind(store, record.id, kinds, \"both\");\n const mapped = linkKindsOf(typeConfig, name) !== undefined;\n\n const stale = [\n ...ofRelationship.filter((link) => !next.has(otherEnd(link))),\n // Unmapped: the link to an identifier the record held before may carry any kind.\n ...(mapped ? [] : (await allLinks()).filter((link) => previous.has(otherEnd(link)) && !next.has(otherEnd(link)))),\n ];\n for (const link of stale) await store.deleteLink({ fromId: link.fromId, toId: link.toId, kind: link.kind });\n\n const linked = new Set(\n (mapped ? await linksOfKind(store, record.id, kinds, \"both\") : await allLinks()).map(otherEnd),\n );\n for (const [id, identifier] of next) {\n if (linked.has(id)) continue;\n await store.putLink({\n fromType: record.type,\n fromId: record.id,\n toType: identifier.type,\n toId: id,\n kind: linkKindFor(typeConfig, name),\n props: {},\n });\n }\n }\n}\n\ntype ImageChange = { url: string; previousUrl?: string };\n\nasync function storeResource(\n store: DeviceStore,\n resource: any,\n pathRootId: string | undefined,\n waiting: Set<string>,\n kept: Set<string>,\n primary: boolean,\n images: ImageChange[],\n): Promise<void> {\n const config = getOfflineConfig();\n if (!resource?.type || !resource?.id) return;\n if (!config.types.some((typeConfig) => typeConfig.module.name === resource.type)) return;\n // A record with unsent local changes keeps them: the next sync, once they are sent, brings\n // the server's version.\n if (waiting.has(recordKeyOf(resource.type, resource.id))) return;\n\n const existing = await store.getRecord(resource.type, resource.id);\n if (existing && existing.base !== null) return;\n const rootId = existing?.rootId ?? (await rootIdForResource(store, config, resource)) ?? pathRootId;\n // A record that belongs to no root record on this device waits for the next sync.\n if (!rootId) return;\n // Only the root records the device keeps are written through (never a player's root record).\n if (!kept.has(rootId)) return;\n\n // An answer can carry a sparse resource (fields limited): it is merged onto what is stored.\n const before = existing?.resource ?? {};\n const merged = {\n ...before,\n ...resource,\n attributes: { ...(before.attributes ?? {}), ...(resource.attributes ?? {}) },\n relationships: { ...(before.relationships ?? {}), ...(resource.relationships ?? {}) },\n };\n\n await store.putRecord({\n type: resource.type,\n id: resource.id,\n rootId,\n resource: merged,\n updatedAt: updatedAtOf(resource) ?? existing?.updatedAt ?? null,\n base: null,\n localOnly: false,\n });\n if (primary) {\n const typeConfig = config.types.find((candidate) => candidate.module.name === resource.type);\n await updateLinks(store, typeConfig, resource, before.relationships, resource.relationships);\n }\n\n const url = imageUrlOf(merged);\n const previousUrl = imageUrlOf(existing?.resource);\n if (url && url !== previousUrl) images.push({ url, previousUrl });\n}\n\n/**\n * After a successful online write, copies the answer into the device copy so it is never behind\n * the GM's own work: the resource and its `included` for POST/PUT/PATCH, the record removed for a\n * DELETE. It never fails the request: a problem is logged and the next sync repairs the copy.\n */\nexport async function writeThrough(request: WriteThroughRequest, response: ApiData): Promise<void> {\n const method = request.method.toUpperCase();\n if (method === \"GET\" || !response.ok) return;\n\n try {\n const config = getOfflineConfig();\n if (!config.getUserId()) return;\n const { path } = splitApiUrl(request.url);\n const store = await getOfflineStore();\n\n if (method === \"DELETE\") {\n for (const typeConfig of config.types) {\n const params = matchPattern([typeConfig.module, \":id\"], path);\n if (params) {\n await store.deleteRecord(typeConfig.module.name, params.id);\n return;\n }\n }\n return;\n }\n\n // A path under a root record of any kind (`<root module>/:rootId/...`).\n const rootSegments = path.split(\"/\").slice(0, 2).join(\"/\");\n const pathRootId = rootKinds(config)\n .map((kind) => matchPattern([kind.module, \":rootId\"], rootSegments)?.rootId)\n .find((rootId) => rootId !== undefined);\n\n const document = response.data;\n const primary = Array.isArray(document?.data) ? document.data : document?.data ? [document.data] : [];\n const waiting = waitingRecordKeys(\n await store.queue(),\n new Set(config.types.map((typeConfig) => typeConfig.module.name)),\n );\n // The root records this device keeps for the signed-in user (stored roots, waiting changes, last\n // sync roots): a write in any other root record (a player's) stores nothing.\n const kept = new Set(await knownRootIds(store));\n const images: ImageChange[] = [];\n await store.transaction(async (transactionStore) => {\n for (const resource of primary) {\n await storeResource(transactionStore, resource, pathRootId, waiting, kept, true, images);\n }\n for (const resource of document?.included ?? []) {\n await storeResource(transactionStore, resource, pathRootId, waiting, kept, false, images);\n }\n });\n // A new image URL of an artwork: downloaded, the old cached image removed (as the sync does).\n for (const image of images) await cacheArtworkImage(image.url, image.previousUrl);\n } catch (error) {\n // A browser that cannot keep the device copy was already warned about once.\n if (error instanceof OfflineUnavailableError) return;\n console.warn(\"[offline] could not copy the answer to the device\", error);\n }\n}\n"]}