@statezero/core 0.1.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 (89) hide show
  1. package/dist/adaptors/react/composables.d.ts +1 -0
  2. package/dist/adaptors/react/composables.js +4 -0
  3. package/dist/adaptors/react/index.d.ts +1 -0
  4. package/dist/adaptors/react/index.js +1 -0
  5. package/dist/adaptors/vue/composables.d.ts +2 -0
  6. package/dist/adaptors/vue/composables.js +36 -0
  7. package/dist/adaptors/vue/index.d.ts +2 -0
  8. package/dist/adaptors/vue/index.js +2 -0
  9. package/dist/adaptors/vue/reactivity.d.ts +18 -0
  10. package/dist/adaptors/vue/reactivity.js +125 -0
  11. package/dist/cli/commands/syncModels.d.ts +132 -0
  12. package/dist/cli/commands/syncModels.js +1040 -0
  13. package/dist/cli/configFileLoader.d.ts +10 -0
  14. package/dist/cli/configFileLoader.js +85 -0
  15. package/dist/cli/index.d.ts +2 -0
  16. package/dist/cli/index.js +14 -0
  17. package/dist/config.d.ts +52 -0
  18. package/dist/config.js +242 -0
  19. package/dist/core/eventReceivers.d.ts +179 -0
  20. package/dist/core/eventReceivers.js +210 -0
  21. package/dist/core/utils.d.ts +8 -0
  22. package/dist/core/utils.js +62 -0
  23. package/dist/filtering/localFiltering.d.ts +116 -0
  24. package/dist/filtering/localFiltering.js +834 -0
  25. package/dist/flavours/django/dates.d.ts +33 -0
  26. package/dist/flavours/django/dates.js +99 -0
  27. package/dist/flavours/django/errors.d.ts +138 -0
  28. package/dist/flavours/django/errors.js +187 -0
  29. package/dist/flavours/django/f.d.ts +6 -0
  30. package/dist/flavours/django/f.js +91 -0
  31. package/dist/flavours/django/files.d.ts +76 -0
  32. package/dist/flavours/django/files.js +338 -0
  33. package/dist/flavours/django/makeApiCall.d.ts +20 -0
  34. package/dist/flavours/django/makeApiCall.js +169 -0
  35. package/dist/flavours/django/manager.d.ts +197 -0
  36. package/dist/flavours/django/manager.js +222 -0
  37. package/dist/flavours/django/model.d.ts +112 -0
  38. package/dist/flavours/django/model.js +253 -0
  39. package/dist/flavours/django/operationFactory.d.ts +65 -0
  40. package/dist/flavours/django/operationFactory.js +216 -0
  41. package/dist/flavours/django/q.d.ts +70 -0
  42. package/dist/flavours/django/q.js +43 -0
  43. package/dist/flavours/django/queryExecutor.d.ts +131 -0
  44. package/dist/flavours/django/queryExecutor.js +468 -0
  45. package/dist/flavours/django/querySet.d.ts +412 -0
  46. package/dist/flavours/django/querySet.js +601 -0
  47. package/dist/flavours/django/tempPk.d.ts +19 -0
  48. package/dist/flavours/django/tempPk.js +48 -0
  49. package/dist/flavours/django/utils.d.ts +19 -0
  50. package/dist/flavours/django/utils.js +29 -0
  51. package/dist/index.d.ts +38 -0
  52. package/dist/index.js +38 -0
  53. package/dist/react-entry.d.ts +2 -0
  54. package/dist/react-entry.js +2 -0
  55. package/dist/reactiveAdaptor.d.ts +24 -0
  56. package/dist/reactiveAdaptor.js +38 -0
  57. package/dist/setup.d.ts +15 -0
  58. package/dist/setup.js +22 -0
  59. package/dist/syncEngine/cache/cache.d.ts +75 -0
  60. package/dist/syncEngine/cache/cache.js +341 -0
  61. package/dist/syncEngine/metrics/metricOptCalcs.d.ts +79 -0
  62. package/dist/syncEngine/metrics/metricOptCalcs.js +284 -0
  63. package/dist/syncEngine/registries/metricRegistry.d.ts +53 -0
  64. package/dist/syncEngine/registries/metricRegistry.js +162 -0
  65. package/dist/syncEngine/registries/modelStoreRegistry.d.ts +11 -0
  66. package/dist/syncEngine/registries/modelStoreRegistry.js +56 -0
  67. package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +55 -0
  68. package/dist/syncEngine/registries/querysetStoreRegistry.js +244 -0
  69. package/dist/syncEngine/stores/metricStore.d.ts +55 -0
  70. package/dist/syncEngine/stores/metricStore.js +222 -0
  71. package/dist/syncEngine/stores/modelStore.d.ts +40 -0
  72. package/dist/syncEngine/stores/modelStore.js +405 -0
  73. package/dist/syncEngine/stores/operation.d.ts +99 -0
  74. package/dist/syncEngine/stores/operation.js +224 -0
  75. package/dist/syncEngine/stores/operationEventHandlers.d.ts +8 -0
  76. package/dist/syncEngine/stores/operationEventHandlers.js +239 -0
  77. package/dist/syncEngine/stores/querysetStore.d.ts +32 -0
  78. package/dist/syncEngine/stores/querysetStore.js +200 -0
  79. package/dist/syncEngine/stores/reactivity.d.ts +3 -0
  80. package/dist/syncEngine/stores/reactivity.js +4 -0
  81. package/dist/syncEngine/stores/utils.d.ts +14 -0
  82. package/dist/syncEngine/stores/utils.js +32 -0
  83. package/dist/syncEngine/sync.d.ts +32 -0
  84. package/dist/syncEngine/sync.js +169 -0
  85. package/dist/vue-entry.d.ts +6 -0
  86. package/dist/vue-entry.js +2 -0
  87. package/license.md +116 -0
  88. package/package.json +123 -0
  89. package/readme.md +222 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Loads configuration from file using cosmiconfig and sets it into the global config singleton.
3
+ *
4
+ * The function searches for a configuration file (e.g. statezero.config.js, .modelsynrc, etc.)
5
+ * and checks if an environment variable (STATEZERO_CONFIG_PATH) overrides the default search path.
6
+ * If a configuration file is found, it is validated and set via configInstance.setConfig().
7
+ *
8
+ * @returns {void}
9
+ */
10
+ export function loadConfigFromFile(): void;
@@ -0,0 +1,85 @@
1
+ import { cosmiconfigSync } from 'cosmiconfig';
2
+ import { configInstance } from '../config.js';
3
+ /**
4
+ * Loads configuration from file using cosmiconfig and sets it into the global config singleton.
5
+ *
6
+ * The function searches for a configuration file (e.g. statezero.config.js, .modelsynrc, etc.)
7
+ * and checks if an environment variable (STATEZERO_CONFIG_PATH) overrides the default search path.
8
+ * If a configuration file is found, it is validated and set via configInstance.setConfig().
9
+ *
10
+ * @returns {void}
11
+ */
12
+ export function loadConfigFromFile() {
13
+ const explorerSync = cosmiconfigSync('statezero', {
14
+ searchPlaces: [
15
+ 'statezero.config.js',
16
+ 'src/statezero.config.js',
17
+ ],
18
+ transform: (result) => {
19
+ if (!result) {
20
+ console.log('No configuration file found.');
21
+ return null;
22
+ }
23
+ console.log(`Successfully loaded config from: ${result.filepath}`);
24
+ // Handle ESM modules with default export
25
+ if (result.config && result.config.__esModule && result.config.default) {
26
+ result.config = result.config.default;
27
+ }
28
+ // Parse any stringified values back to their original format
29
+ const parseNestedValues = (obj) => {
30
+ if (!obj || typeof obj !== 'object')
31
+ return obj;
32
+ Object.keys(obj).forEach(key => {
33
+ const value = obj[key];
34
+ // Don't try to parse functions
35
+ if (typeof value === 'string' && !value.includes('Function')) {
36
+ try {
37
+ // Check if it's a stringified value
38
+ if ((value.startsWith('"') && value.endsWith('"')) ||
39
+ (value === 'true' || value === 'false')) {
40
+ obj[key] = JSON.parse(value);
41
+ }
42
+ }
43
+ catch (e) {
44
+ // If parsing fails, keep the original value
45
+ }
46
+ }
47
+ // Recursively parse nested objects
48
+ if (value && typeof value === 'object') {
49
+ parseNestedValues(value);
50
+ }
51
+ });
52
+ return obj;
53
+ };
54
+ // Parse any stringified values in the config
55
+ if (result.config && typeof result.config === 'object') {
56
+ parseNestedValues(result.config);
57
+ }
58
+ return result;
59
+ }
60
+ });
61
+ const envConfigPath = process.env.STATEZERO_CONFIG_PATH;
62
+ let result = null;
63
+ if (envConfigPath) {
64
+ console.log(`Attempting to load config from environment path: ${envConfigPath}`);
65
+ try {
66
+ result = explorerSync.load(envConfigPath);
67
+ }
68
+ catch (error) {
69
+ console.log(`Failed to load from environment path: ${error.message}`);
70
+ }
71
+ }
72
+ if (!result) {
73
+ console.log('Searching for statezero configuration files...');
74
+ result = explorerSync.search();
75
+ }
76
+ if (result && result.config) {
77
+ // Apply the configuration
78
+ configInstance.setConfig(result.config);
79
+ console.log(`Configuration set from ${result.filepath}`);
80
+ }
81
+ else {
82
+ console.log('Could not find configuration, using default empty config');
83
+ configInstance.setConfig({ backendConfigs: {} });
84
+ }
85
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+ import yargs from 'yargs';
5
+ import { hideBin } from 'yargs/helpers';
6
+ import { generateSchema } from './commands/syncModels.js';
7
+ yargs(hideBin(process.argv))
8
+ .command('sync-models', 'Generate model classes from the openapi schema',
9
+ // No CLI options since API_URL and GENERATED_TYPES_DIR are read from .env.
10
+ {}, async () => {
11
+ await generateSchema({});
12
+ })
13
+ .help()
14
+ .argv;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Sets the entire configuration, validating it before storing.
3
+ * If the configuration is invalid, it throws a ConfigError.
4
+ */
5
+ export function setConfig(newConfig: any): void;
6
+ /**
7
+ * Retrieves the validated configuration.
8
+ * If no configuration has been set, it throws a ConfigError.
9
+ */
10
+ export function getConfig(): any;
11
+ /**
12
+ * Merges a partial override into an existing backend config.
13
+ */
14
+ export function setBackendConfig(backendKey: any, newConfig: any): void;
15
+ /**
16
+ * Initializes the event receiver based on the configuration.
17
+ */
18
+ export function initializeEventReceiver(backendKey?: string): PusherEventReceiver | null;
19
+ /**
20
+ * Initializes event receivers for all configured backends.
21
+ *
22
+ * @returns {Object} Map of backend keys to their initialized event receivers
23
+ * @throws {ConfigError} If configuration is not set or if initialization fails
24
+ */
25
+ export function initializeAllEventReceivers(): Object;
26
+ /**
27
+ * Registers the function used to retrieve model classes.
28
+ * This should be called once during application setup after setConfig.
29
+ * @param {Function} getterFn - The getModelClass function imported from model-registry.js
30
+ */
31
+ export function registerModelGetter(getterFn: Function): void;
32
+ /**
33
+ * Get a model class by name using the registered getter.
34
+ *
35
+ * @param {string} modelName - The model name (e.g., 'app.MyModel')
36
+ * @param {string} configKey - The config key (backend name)
37
+ * @returns {Function|null} - The model class or null if not found
38
+ */
39
+ export function getModelClass(modelName: string, configKey: string): Function | null;
40
+ export namespace liveConfig {
41
+ let backendConfigs: {};
42
+ }
43
+ export namespace configInstance {
44
+ export { setConfig };
45
+ export { getConfig };
46
+ export { setBackendConfig };
47
+ export { initializeEventReceiver };
48
+ export { registerModelGetter };
49
+ export { getModelClass };
50
+ }
51
+ export default configInstance;
52
+ import { PusherEventReceiver } from './core/eventReceivers.js';
package/dist/config.js ADDED
@@ -0,0 +1,242 @@
1
+ import { z } from 'zod';
2
+ import { ConfigError } from './flavours/django/errors.js';
3
+ import { PusherEventReceiver, setEventReceiver } from './core/eventReceivers.js';
4
+ // The live configuration object. By default it is empty.
5
+ export let liveConfig = {
6
+ backendConfigs: {}
7
+ };
8
+ // --- Zod Schemas ---
9
+ const pusherSchema = z.object({
10
+ clientOptions: z.object({
11
+ appKey: z.string({ required_error: 'Pusher appKey is required' }),
12
+ cluster: z.string({ required_error: 'Pusher cluster is required' }),
13
+ forceTLS: z.boolean().optional(),
14
+ authEndpoint: z.string()
15
+ .url('Pusher authentication endpoint URL is required'),
16
+ getAuthHeaders: z.function().optional()
17
+ .refine((fn) => fn === undefined || typeof fn === 'function', 'getAuthHeaders must be a function if provided')
18
+ })
19
+ });
20
+ const eventConfigSchema = z.object({
21
+ type: z.enum(['websocket', 'pusher', 'none']),
22
+ websocketUrl: z.string().url().optional(),
23
+ pusher: pusherSchema.optional(),
24
+ hotpaths: z.array(z.string()).default(['default'])
25
+ }).superRefine((data, ctx) => {
26
+ // Conditional validation based on type
27
+ if (data.type === 'websocket') {
28
+ if (!data.websocketUrl) {
29
+ ctx.addIssue({
30
+ code: z.ZodIssueCode.custom,
31
+ path: ['websocketUrl'],
32
+ message: 'WebSocket URL is required for WebSocket event receiver'
33
+ });
34
+ }
35
+ }
36
+ if (data.type === 'pusher') {
37
+ if (!data.pusher) {
38
+ ctx.addIssue({
39
+ code: z.ZodIssueCode.custom,
40
+ path: ['pusher'],
41
+ message: 'Pusher configuration is required for Pusher event receiver'
42
+ });
43
+ }
44
+ }
45
+ });
46
+ const backendSchema = z.object({
47
+ API_URL: z.string().url('API_URL must be a valid URL'),
48
+ GENERATED_TYPES_DIR: z.string({ required_error: 'GENERATED_TYPES_DIR is required' }),
49
+ BACKEND_TZ: z.string().optional(),
50
+ fileUploadMode: z.enum(['server', 's3']).default('server'),
51
+ getAuthHeaders: z.function().optional()
52
+ .refine((fn) => fn === undefined || typeof fn === 'function', 'getAuthHeaders must be a function if provided'),
53
+ eventInterceptor: z.function().optional()
54
+ .refine((fn) => fn === undefined || typeof fn === 'function', 'eventInterceptor must be a function if provided'),
55
+ events: z.lazy(() => eventConfigSchema.optional())
56
+ });
57
+ const configSchema = z.object({
58
+ backendConfigs: z.record(z.string(), backendSchema)
59
+ .refine((configs) => {
60
+ // Validate each backend config
61
+ for (const [key, backend] of Object.entries(configs)) {
62
+ const result = backendSchema.safeParse(backend);
63
+ if (!result.success) {
64
+ return false;
65
+ }
66
+ }
67
+ return true;
68
+ }, (configs) => {
69
+ // Generate detailed error message
70
+ const errors = [];
71
+ for (const [key, backend] of Object.entries(configs)) {
72
+ const result = backendSchema.safeParse(backend);
73
+ if (!result.success) {
74
+ const errorMessages = result.error.errors.map(err => err.message);
75
+ errors.push(`Backend "${key}" is invalid: ${errorMessages.join(', ')}`);
76
+ }
77
+ }
78
+ return { message: errors.join('; ') };
79
+ })
80
+ });
81
+ // Internal variable to hold the validated configuration.
82
+ let config = null;
83
+ /**
84
+ * Sets the entire configuration, validating it before storing.
85
+ * If the configuration is invalid, it throws a ConfigError.
86
+ */
87
+ export function setConfig(newConfig) {
88
+ liveConfig = newConfig;
89
+ const result = configSchema.safeParse(liveConfig);
90
+ if (!result.success) {
91
+ const errorMessages = result.error.errors.map(err => err.message);
92
+ throw new ConfigError(`Error setting configuration: ${errorMessages.join(', ')}`);
93
+ }
94
+ config = result.data;
95
+ }
96
+ /**
97
+ * Retrieves the validated configuration.
98
+ * If no configuration has been set, it throws a ConfigError.
99
+ */
100
+ export function getConfig() {
101
+ if (!config) {
102
+ throw new ConfigError('Configuration not set. Please call setConfig() with a valid configuration.');
103
+ }
104
+ return config;
105
+ }
106
+ /**
107
+ * Merges a partial override into an existing backend config.
108
+ */
109
+ export function setBackendConfig(backendKey, newConfig) {
110
+ try {
111
+ const cfg = getConfig();
112
+ if (!cfg.backendConfigs[backendKey]) {
113
+ throw new ConfigError(`Backend "${backendKey}" not found in configuration.`);
114
+ }
115
+ const merged = { ...cfg.backendConfigs[backendKey], ...newConfig };
116
+ const result = backendSchema.safeParse(merged);
117
+ if (!result.success) {
118
+ const errorMessages = result.error.errors.map(err => err.message);
119
+ throw new ConfigError(`Invalid backend configuration: ${errorMessages.join(', ')}`);
120
+ }
121
+ cfg.backendConfigs[backendKey] = result.data;
122
+ }
123
+ catch (error) {
124
+ if (error instanceof ConfigError) {
125
+ throw error;
126
+ }
127
+ throw new ConfigError(error.message || 'Invalid backend configuration');
128
+ }
129
+ }
130
+ /**
131
+ * Initializes the event receiver based on the configuration.
132
+ */
133
+ export function initializeEventReceiver(backendKey = 'default') {
134
+ try {
135
+ const cfg = getConfig();
136
+ if (!cfg.backendConfigs[backendKey]) {
137
+ throw new ConfigError(`Backend "${backendKey}" not found in configuration.`);
138
+ }
139
+ const backendConfig = cfg.backendConfigs[backendKey];
140
+ if (!backendConfig.events) {
141
+ return null;
142
+ }
143
+ let receiver = null;
144
+ switch (backendConfig.events.type) {
145
+ case 'pusher':
146
+ if (!backendConfig.events.pusher || !backendConfig.events.pusher.clientOptions) {
147
+ throw new ConfigError('Pusher client options are required for Pusher event receiver.');
148
+ }
149
+ if (!backendConfig.events.pusher.clientOptions.authEndpoint) {
150
+ throw new ConfigError('Pusher auth endpoint is required for Pusher event receiver.');
151
+ }
152
+ const clientOptions = {
153
+ ...backendConfig.events.pusher.clientOptions,
154
+ getAuthHeaders: backendConfig.events.pusher.clientOptions.getAuthHeaders || backendConfig.getAuthHeaders
155
+ };
156
+ // Pass the backendKey to the constructor
157
+ receiver = new PusherEventReceiver({ clientOptions }, backendKey);
158
+ break;
159
+ case 'none':
160
+ return null;
161
+ default:
162
+ throw new ConfigError(`Unknown event receiver type: ${backendConfig.events.type}`);
163
+ }
164
+ if (receiver) {
165
+ // Pass the backendKey to associate the receiver with this backend
166
+ setEventReceiver(backendKey, receiver);
167
+ }
168
+ return receiver;
169
+ }
170
+ catch (error) {
171
+ if (error instanceof ConfigError) {
172
+ throw error;
173
+ }
174
+ throw new ConfigError(`Failed to initialize event receiver: ${error.message}`);
175
+ }
176
+ }
177
+ /**
178
+ * Initializes event receivers for all configured backends.
179
+ *
180
+ * @returns {Object} Map of backend keys to their initialized event receivers
181
+ * @throws {ConfigError} If configuration is not set or if initialization fails
182
+ */
183
+ export function initializeAllEventReceivers() {
184
+ try {
185
+ const cfg = getConfig();
186
+ const receivers = {};
187
+ // Initialize event receivers for each backend configuration
188
+ Object.keys(cfg.backendConfigs).forEach(backendKey => {
189
+ try {
190
+ receivers[backendKey] = initializeEventReceiver(backendKey);
191
+ }
192
+ catch (error) {
193
+ console.warn(`Failed to initialize event receiver for backend "${backendKey}": ${error.message}`);
194
+ }
195
+ });
196
+ return receivers;
197
+ }
198
+ catch (error) {
199
+ throw new ConfigError(`Failed to initialize event receivers: ${error.message}`);
200
+ }
201
+ }
202
+ // --- Declare the variable to hold the registered model getter ---
203
+ let modelGetter = null;
204
+ /**
205
+ * Registers the function used to retrieve model classes.
206
+ * This should be called once during application setup after setConfig.
207
+ * @param {Function} getterFn - The getModelClass function imported from model-registry.js
208
+ */
209
+ export function registerModelGetter(getterFn) {
210
+ if (typeof getterFn !== 'function') {
211
+ throw new ConfigError('Provided model getter must be a function.');
212
+ }
213
+ modelGetter = getterFn;
214
+ }
215
+ /**
216
+ * Get a model class by name using the registered getter.
217
+ *
218
+ * @param {string} modelName - The model name (e.g., 'app.MyModel')
219
+ * @param {string} configKey - The config key (backend name)
220
+ * @returns {Function|null} - The model class or null if not found
221
+ */
222
+ export function getModelClass(modelName, configKey) {
223
+ if (!modelGetter) {
224
+ // Optionally check if config is set first
225
+ // getConfig(); // This will throw if config isn't set
226
+ throw new ConfigError('Model registry not registered. Please call registerModelGetter() with the function from model-registry.js during app initialization.');
227
+ }
228
+ // Delegate to the function provided by the user from model-registry.js
229
+ return modelGetter(modelName, configKey);
230
+ }
231
+ /**
232
+ * Exposes a singleton object for configuration functionality.
233
+ */
234
+ export const configInstance = {
235
+ setConfig,
236
+ getConfig,
237
+ setBackendConfig,
238
+ initializeEventReceiver,
239
+ registerModelGetter,
240
+ getModelClass
241
+ };
242
+ export default configInstance;
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Set an event receiver for a specific backend.
3
+ * @param {string} configKey - The backend configuration key
4
+ * @param {EventReceiver} receiver - The event receiver instance
5
+ */
6
+ export function setEventReceiver(configKey: string, receiver: EventReceiver): void;
7
+ /**
8
+ * Get the event receiver for a specific backend.
9
+ * @param {string} configKey - The backend configuration key
10
+ * @returns {EventReceiver|null}
11
+ */
12
+ export function getEventReceiver(configKey?: string): EventReceiver | null;
13
+ /**
14
+ * Get all registered event receivers.
15
+ * @returns {Map<string, EventReceiver>}
16
+ */
17
+ export function getAllEventReceivers(): Map<string, EventReceiver>;
18
+ /**
19
+ * Set a custom namespace resolver function for a specific backend.
20
+ * @param {string} configKey - The backend configuration key
21
+ * @param {NamespaceResolver} resolver
22
+ */
23
+ export function setNamespaceResolver(configKey: string, resolver: NamespaceResolver): void;
24
+ /**
25
+ * Event types that can be received from the server.
26
+ */
27
+ export type EventType = string;
28
+ export namespace EventType {
29
+ let CREATE: string;
30
+ let UPDATE: string;
31
+ let DELETE: string;
32
+ let BULK_UPDATE: string;
33
+ let BULK_DELETE: string;
34
+ }
35
+ /**
36
+ * Callback for handling model events.
37
+ * @callback EventHandler
38
+ * @param {ModelEvent} event - The event object.
39
+ */
40
+ /**
41
+ * A namespace resolver function.
42
+ * @callback NamespaceResolver
43
+ * @param {string} modelName - The model name.
44
+ * @returns {string} The namespace.
45
+ */
46
+ /**
47
+ * Options for instantiating a Pusher client.
48
+ * @typedef {Object} PusherClientOptions
49
+ * @property {string} appKey
50
+ * @property {string} cluster
51
+ * @property {boolean} [forceTLS]
52
+ * @property {string} authEndpoint
53
+ * @property {function(): Object<string, string>} [getAuthHeaders]
54
+ */
55
+ /**
56
+ * Configuration options for Pusher event receivers.
57
+ * @typedef {Object} PusherReceiverOptions
58
+ * @property {PusherClientOptions} clientOptions
59
+ * @property {function(string): string} [formatChannelName] - Optional channel name formatter. Default: (namespace) => `private-${namespace}`
60
+ * @property {NamespaceResolver} [namespaceResolver] - Optional namespace resolver. Default: (modelName) => modelName.
61
+ */
62
+ /**
63
+ * Implementation of EventReceiver that uses Pusher.
64
+ */
65
+ export class PusherEventReceiver {
66
+ /**
67
+ * @param {PusherReceiverOptions} options
68
+ * @param {string} configKey - The backend configuration key
69
+ */
70
+ constructor(options: PusherReceiverOptions, configKey: string);
71
+ configKey: string;
72
+ pusherClient: Pusher;
73
+ formatChannelName: (ns: string) => string;
74
+ namespaceResolver: (modelName: string) => string;
75
+ channels: Map<any, any>;
76
+ eventHandlers: Set<any>;
77
+ /**
78
+ * Set the namespace resolver function.
79
+ * @param {NamespaceResolver} resolver
80
+ */
81
+ setNamespaceResolver(resolver: NamespaceResolver): void;
82
+ /**
83
+ * Connect to Pusher (no-op since Pusher handles connection automatically).
84
+ */
85
+ connect(): void;
86
+ /**
87
+ * Subscribe to events for a specific namespace.
88
+ * @param {string} namespace
89
+ */
90
+ subscribe(namespace: string): void;
91
+ unsubscribe(namespace: any): void;
92
+ /**
93
+ * Disconnect from Pusher.
94
+ */
95
+ disconnect(): void;
96
+ /**
97
+ * Add handler for model events
98
+ * @param {EventHandler} handler
99
+ */
100
+ addModelEventHandler(handler: EventHandler): void;
101
+ /**
102
+ * Legacy method - adds event handler for backwards compatibility
103
+ * @param {EventHandler} handler
104
+ */
105
+ addEventHandler(handler: EventHandler): void;
106
+ /**
107
+ * Remove an event handler callback.
108
+ * @param {EventHandler} handler
109
+ */
110
+ removeEventHandler(handler: EventHandler): void;
111
+ /**
112
+ * Get namespace from model name using the resolver.
113
+ * @param {string} modelName
114
+ * @returns {string}
115
+ */
116
+ getNamespace(modelName: string): string;
117
+ }
118
+ /**
119
+ * Structure of events received from the server.
120
+ */
121
+ export type ModelEvent = {
122
+ /**
123
+ * - Support both frontend (type) and backend (event) naming conventions.
124
+ */
125
+ type?: string | undefined;
126
+ event?: string | undefined;
127
+ model: string;
128
+ data?: any;
129
+ operationId?: string | undefined;
130
+ namespace?: string | undefined;
131
+ /**
132
+ * - For bulk events.
133
+ */
134
+ instances?: (string | number)[] | undefined;
135
+ pk_field_name?: string | undefined;
136
+ /**
137
+ * - The backend configuration key this event is associated with.
138
+ */
139
+ configKey?: string | undefined;
140
+ /**
141
+ * - Additional open-ended keys.
142
+ */
143
+ key?: any;
144
+ };
145
+ /**
146
+ * Callback for handling model events.
147
+ */
148
+ export type EventHandler = (event: ModelEvent) => any;
149
+ /**
150
+ * A namespace resolver function.
151
+ */
152
+ export type NamespaceResolver = (modelName: string) => string;
153
+ /**
154
+ * Options for instantiating a Pusher client.
155
+ */
156
+ export type PusherClientOptions = {
157
+ appKey: string;
158
+ cluster: string;
159
+ forceTLS?: boolean | undefined;
160
+ authEndpoint: string;
161
+ getAuthHeaders?: (() => {
162
+ [x: string]: string;
163
+ }) | undefined;
164
+ };
165
+ /**
166
+ * Configuration options for Pusher event receivers.
167
+ */
168
+ export type PusherReceiverOptions = {
169
+ clientOptions: PusherClientOptions;
170
+ /**
171
+ * - Optional channel name formatter. Default: (namespace) => `private-${namespace}`
172
+ */
173
+ formatChannelName?: ((arg0: string) => string) | undefined;
174
+ /**
175
+ * - Optional namespace resolver. Default: (modelName) => modelName.
176
+ */
177
+ namespaceResolver?: NamespaceResolver | undefined;
178
+ };
179
+ import Pusher from 'pusher-js';