@protoc-gen-go-wasmjs/runtime 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +184 -0
- package/README.md +82 -0
- package/dist/browser/index.d.mts +41 -0
- package/dist/browser/index.d.ts +41 -0
- package/dist/browser/index.js +88 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/index.mjs +86 -0
- package/dist/browser/index.mjs.map +1 -0
- package/dist/client/index.d.mts +169 -0
- package/dist/client/index.d.ts +169 -0
- package/dist/client/index.js +518 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/index.mjs +513 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/factory-DqksufjU.d.mts +23 -0
- package/dist/factory-DqksufjU.d.ts +23 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +764 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +753 -0
- package/dist/index.mjs.map +1 -0
- package/dist/schema/index.d.mts +108 -0
- package/dist/schema/index.d.ts +108 -0
- package/dist/schema/index.js +227 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/index.mjs +223 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/types/index.d.mts +90 -0
- package/dist/types/index.d.ts +90 -0
- package/dist/types/index.js +26 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.mjs +23 -0
- package/dist/types/index.mjs.map +1 -0
- package/package.json +78 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/browser/service-manager.ts
|
|
4
|
+
var BrowserServiceManager = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.processing = false;
|
|
7
|
+
this.serviceImplementations = /* @__PURE__ */ new Map();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Register a browser service implementation
|
|
11
|
+
*/
|
|
12
|
+
registerService(name, implementation) {
|
|
13
|
+
this.serviceImplementations.set(name, implementation);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Set the WASM module reference
|
|
17
|
+
*/
|
|
18
|
+
setWasmModule(wasmModule) {
|
|
19
|
+
this.wasmModule = wasmModule;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Start processing browser service calls
|
|
23
|
+
*/
|
|
24
|
+
async startProcessing() {
|
|
25
|
+
if (this.processing) return;
|
|
26
|
+
this.processing = true;
|
|
27
|
+
while (this.processing) {
|
|
28
|
+
const call = this.getNextBrowserCall();
|
|
29
|
+
if (!call) {
|
|
30
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
this.processCall(call);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Process a single browser service call asynchronously
|
|
38
|
+
*/
|
|
39
|
+
async processCall(call) {
|
|
40
|
+
try {
|
|
41
|
+
const service = this.serviceImplementations.get(call.service);
|
|
42
|
+
if (!service) {
|
|
43
|
+
throw new Error(`No implementation registered for service: ${call.service}`);
|
|
44
|
+
}
|
|
45
|
+
const methodName = call.method.charAt(0).toLowerCase() + call.method.slice(1);
|
|
46
|
+
const method = service[methodName];
|
|
47
|
+
if (!method) {
|
|
48
|
+
throw new Error(`Method ${methodName} not found on service ${call.service}`);
|
|
49
|
+
}
|
|
50
|
+
const request = JSON.parse(call.request);
|
|
51
|
+
const response = await Promise.resolve(method.call(service, request));
|
|
52
|
+
console.log(`DEBUG: Browser service response for ${call.service}.${call.method}:`, response);
|
|
53
|
+
const jsonResponse = JSON.stringify(response);
|
|
54
|
+
console.log(`DEBUG: JSON stringified response:`, jsonResponse);
|
|
55
|
+
this.deliverBrowserResponse(call.id, jsonResponse, null);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
this.deliverBrowserResponse(call.id, null, error.message || String(error));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stop processing browser service calls
|
|
62
|
+
*/
|
|
63
|
+
stopProcessing() {
|
|
64
|
+
this.processing = false;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get the next browser call from WASM
|
|
68
|
+
*/
|
|
69
|
+
getNextBrowserCall() {
|
|
70
|
+
if (typeof window.__wasmGetNextBrowserCall === "function") {
|
|
71
|
+
return window.__wasmGetNextBrowserCall();
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Deliver a response back to WASM (called internally)
|
|
77
|
+
*/
|
|
78
|
+
deliverBrowserResponse(callId, response, error) {
|
|
79
|
+
if (!window.__wasmDeliverBrowserResponse) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return window.__wasmDeliverBrowserResponse(callId, response, error);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// src/schema/types.ts
|
|
87
|
+
var FieldType = /* @__PURE__ */ ((FieldType2) => {
|
|
88
|
+
FieldType2["STRING"] = "string";
|
|
89
|
+
FieldType2["NUMBER"] = "number";
|
|
90
|
+
FieldType2["BOOLEAN"] = "boolean";
|
|
91
|
+
FieldType2["MESSAGE"] = "message";
|
|
92
|
+
FieldType2["REPEATED"] = "repeated";
|
|
93
|
+
FieldType2["MAP"] = "map";
|
|
94
|
+
FieldType2["ONEOF"] = "oneof";
|
|
95
|
+
return FieldType2;
|
|
96
|
+
})(FieldType || {});
|
|
97
|
+
|
|
98
|
+
// src/schema/base-deserializer.ts
|
|
99
|
+
var BaseDeserializer = class {
|
|
100
|
+
constructor(schemaRegistry, factory) {
|
|
101
|
+
this.schemaRegistry = schemaRegistry;
|
|
102
|
+
this.factory = factory;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Deserialize an object using schema information
|
|
106
|
+
* @param instance The target instance to populate
|
|
107
|
+
* @param data The source data to deserialize from
|
|
108
|
+
* @param messageType The fully qualified message type (e.g., "library.v1.Book")
|
|
109
|
+
* @returns The populated instance
|
|
110
|
+
*/
|
|
111
|
+
deserialize(instance, data, messageType) {
|
|
112
|
+
if (!data || typeof data !== "object") {
|
|
113
|
+
return instance;
|
|
114
|
+
}
|
|
115
|
+
const schema = this.schemaRegistry[messageType];
|
|
116
|
+
if (!schema) {
|
|
117
|
+
return this.fallbackDeserialize(instance, data);
|
|
118
|
+
}
|
|
119
|
+
for (const fieldSchema of schema.fields) {
|
|
120
|
+
const fieldValue = data[fieldSchema.name];
|
|
121
|
+
if (fieldValue === null || fieldValue === void 0) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
this.deserializeField(instance, fieldSchema, fieldValue);
|
|
125
|
+
}
|
|
126
|
+
return instance;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Deserialize a single field based on its schema
|
|
130
|
+
*/
|
|
131
|
+
deserializeField(instance, fieldSchema, fieldValue) {
|
|
132
|
+
const fieldName = fieldSchema.name;
|
|
133
|
+
switch (fieldSchema.type) {
|
|
134
|
+
case "string" /* STRING */:
|
|
135
|
+
case "number" /* NUMBER */:
|
|
136
|
+
case "boolean" /* BOOLEAN */:
|
|
137
|
+
instance[fieldName] = fieldValue;
|
|
138
|
+
break;
|
|
139
|
+
case "message" /* MESSAGE */:
|
|
140
|
+
if (fieldSchema.repeated) {
|
|
141
|
+
instance[fieldName] = this.deserializeMessageArray(
|
|
142
|
+
fieldValue,
|
|
143
|
+
fieldSchema.messageType,
|
|
144
|
+
instance,
|
|
145
|
+
fieldName
|
|
146
|
+
);
|
|
147
|
+
} else {
|
|
148
|
+
instance[fieldName] = this.deserializeMessageField(
|
|
149
|
+
fieldValue,
|
|
150
|
+
fieldSchema.messageType,
|
|
151
|
+
instance,
|
|
152
|
+
fieldName
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
case "repeated" /* REPEATED */:
|
|
157
|
+
if (Array.isArray(fieldValue)) {
|
|
158
|
+
instance[fieldName] = [...fieldValue];
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
case "oneof" /* ONEOF */:
|
|
162
|
+
instance[fieldName] = fieldValue;
|
|
163
|
+
break;
|
|
164
|
+
case "map" /* MAP */:
|
|
165
|
+
instance[fieldName] = { ...fieldValue };
|
|
166
|
+
break;
|
|
167
|
+
default:
|
|
168
|
+
instance[fieldName] = fieldValue;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Deserialize a single message field
|
|
174
|
+
*/
|
|
175
|
+
deserializeMessageField(fieldValue, messageType, parent, attributeName) {
|
|
176
|
+
let factoryMethod;
|
|
177
|
+
if (this.factory.getFactoryMethod) {
|
|
178
|
+
factoryMethod = this.factory.getFactoryMethod(messageType);
|
|
179
|
+
} else {
|
|
180
|
+
const factoryMethodName = this.getFactoryMethodName(messageType);
|
|
181
|
+
factoryMethod = this.factory[factoryMethodName];
|
|
182
|
+
}
|
|
183
|
+
if (factoryMethod) {
|
|
184
|
+
const result = factoryMethod(parent, attributeName, void 0, fieldValue);
|
|
185
|
+
if (result.fullyLoaded) {
|
|
186
|
+
return result.instance;
|
|
187
|
+
} else {
|
|
188
|
+
return this.deserialize(result.instance, fieldValue, messageType);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return this.fallbackDeserialize({}, fieldValue);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Deserialize an array of message objects
|
|
195
|
+
*/
|
|
196
|
+
deserializeMessageArray(fieldValue, messageType, parent, attributeName) {
|
|
197
|
+
if (!Array.isArray(fieldValue)) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
let factoryMethod;
|
|
201
|
+
if (this.factory.getFactoryMethod) {
|
|
202
|
+
factoryMethod = this.factory.getFactoryMethod(messageType);
|
|
203
|
+
} else {
|
|
204
|
+
const factoryMethodName = this.getFactoryMethodName(messageType);
|
|
205
|
+
factoryMethod = this.factory[factoryMethodName];
|
|
206
|
+
}
|
|
207
|
+
return fieldValue.map((item, index) => {
|
|
208
|
+
if (factoryMethod) {
|
|
209
|
+
const result = factoryMethod(parent, attributeName, index, item);
|
|
210
|
+
if (result.fullyLoaded) {
|
|
211
|
+
return result.instance;
|
|
212
|
+
} else {
|
|
213
|
+
return this.deserialize(result.instance, item, messageType);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return this.fallbackDeserialize({}, item);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Convert message type to factory method name
|
|
221
|
+
* "library.v1.Book" -> "newBook"
|
|
222
|
+
*/
|
|
223
|
+
getFactoryMethodName(messageType) {
|
|
224
|
+
const parts = messageType.split(".");
|
|
225
|
+
const typeName = parts[parts.length - 1];
|
|
226
|
+
return "new" + typeName;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Fallback deserializer for when no schema is available
|
|
230
|
+
*/
|
|
231
|
+
fallbackDeserialize(instance, data) {
|
|
232
|
+
if (!data || typeof data !== "object") {
|
|
233
|
+
return instance;
|
|
234
|
+
}
|
|
235
|
+
for (const [key, value] of Object.entries(data)) {
|
|
236
|
+
if (value !== null && value !== void 0) {
|
|
237
|
+
instance[key] = value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return instance;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Create and deserialize a new instance of a message type
|
|
244
|
+
*/
|
|
245
|
+
createAndDeserialize(messageType, data) {
|
|
246
|
+
let factoryMethod;
|
|
247
|
+
if (this.factory.getFactoryMethod) {
|
|
248
|
+
factoryMethod = this.factory.getFactoryMethod(messageType);
|
|
249
|
+
} else {
|
|
250
|
+
const factoryMethodName = this.getFactoryMethodName(messageType);
|
|
251
|
+
factoryMethod = this.factory[factoryMethodName];
|
|
252
|
+
}
|
|
253
|
+
if (!factoryMethod) {
|
|
254
|
+
throw new Error(`Could not find factory method to deserialize: ${messageType}`);
|
|
255
|
+
}
|
|
256
|
+
const result = factoryMethod(void 0, void 0, void 0, data);
|
|
257
|
+
if (result.fullyLoaded) {
|
|
258
|
+
return result.instance;
|
|
259
|
+
} else {
|
|
260
|
+
return this.deserialize(result.instance, data, messageType);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/schema/base-registry.ts
|
|
266
|
+
var BaseSchemaRegistry = class {
|
|
267
|
+
constructor(schemaRegistry) {
|
|
268
|
+
this.schemaRegistry = schemaRegistry;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Get schema for a message type
|
|
272
|
+
*/
|
|
273
|
+
getSchema(messageType) {
|
|
274
|
+
return this.schemaRegistry[messageType];
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get field schema by name
|
|
278
|
+
*/
|
|
279
|
+
getFieldSchema(messageType, fieldName) {
|
|
280
|
+
const schema = this.getSchema(messageType);
|
|
281
|
+
return schema?.fields.find((field) => field.name === fieldName);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get field schema by proto field ID
|
|
285
|
+
*/
|
|
286
|
+
getFieldSchemaById(messageType, fieldId) {
|
|
287
|
+
const schema = this.getSchema(messageType);
|
|
288
|
+
return schema?.fields.find((field) => field.id === fieldId);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Check if field is part of a oneof group
|
|
292
|
+
*/
|
|
293
|
+
isOneofField(messageType, fieldName) {
|
|
294
|
+
const fieldSchema = this.getFieldSchema(messageType, fieldName);
|
|
295
|
+
return fieldSchema?.oneofGroup !== void 0;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get all fields in a oneof group
|
|
299
|
+
*/
|
|
300
|
+
getOneofFields(messageType, oneofGroup) {
|
|
301
|
+
const schema = this.getSchema(messageType);
|
|
302
|
+
return schema?.fields.filter((field) => field.oneofGroup === oneofGroup) || [];
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// src/client/types.ts
|
|
307
|
+
var WasmError = class extends Error {
|
|
308
|
+
constructor(message, methodPath) {
|
|
309
|
+
super(message);
|
|
310
|
+
this.methodPath = methodPath;
|
|
311
|
+
this.name = "WasmError";
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// src/client/base-client.ts
|
|
316
|
+
var WASMServiceClient = class {
|
|
317
|
+
constructor() {
|
|
318
|
+
this.wasmLoadPromise = null;
|
|
319
|
+
this.browserServiceManager = null;
|
|
320
|
+
this.browserServiceManager = new BrowserServiceManager();
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Register a browser service implementation
|
|
324
|
+
* Can be used to register browser services from any package
|
|
325
|
+
*/
|
|
326
|
+
registerBrowserService(name, implementation) {
|
|
327
|
+
if (!this.browserServiceManager) {
|
|
328
|
+
throw new Error("Browser service manager not initialized");
|
|
329
|
+
}
|
|
330
|
+
this.browserServiceManager.registerService(name, implementation);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Check if WASM is ready for operations
|
|
334
|
+
*/
|
|
335
|
+
isReady() {
|
|
336
|
+
return this.wasm !== null && this.wasm !== void 0;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Wait for WASM to be ready (use during initialization)
|
|
340
|
+
*/
|
|
341
|
+
async waitUntilReady() {
|
|
342
|
+
if (!this.wasmLoadPromise) {
|
|
343
|
+
throw new Error("WASM loading not started. Call loadWasm() first.");
|
|
344
|
+
}
|
|
345
|
+
await this.wasmLoadPromise;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Internal method to call WASM functions with JSON conversion
|
|
349
|
+
*/
|
|
350
|
+
callMethod(methodPath, request) {
|
|
351
|
+
this.ensureWASMLoaded();
|
|
352
|
+
try {
|
|
353
|
+
const jsonReq = JSON.parse(JSON.stringify(request));
|
|
354
|
+
const wasmMethod = this.getWasmMethod(methodPath);
|
|
355
|
+
const wasmResponse = wasmMethod(JSON.stringify(jsonReq));
|
|
356
|
+
if (!wasmResponse.success) {
|
|
357
|
+
throw new WasmError(wasmResponse.message, methodPath);
|
|
358
|
+
}
|
|
359
|
+
return wasmResponse.data;
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (error instanceof WasmError) {
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
throw new WasmError(
|
|
365
|
+
`Call error: ${error instanceof Error ? error.message : String(error)}`,
|
|
366
|
+
methodPath
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Internal method to call async WASM functions with callback
|
|
372
|
+
*/
|
|
373
|
+
callMethodWithCallback(methodPath, request, callback) {
|
|
374
|
+
this.ensureWASMLoaded();
|
|
375
|
+
try {
|
|
376
|
+
const jsonReq = JSON.parse(JSON.stringify(request));
|
|
377
|
+
const wasmMethod = this.getWasmMethod(methodPath);
|
|
378
|
+
const wasmResponse = wasmMethod(JSON.stringify(jsonReq), callback);
|
|
379
|
+
if (!wasmResponse.success) {
|
|
380
|
+
throw new WasmError(wasmResponse.message, methodPath);
|
|
381
|
+
}
|
|
382
|
+
return Promise.resolve();
|
|
383
|
+
} catch (error) {
|
|
384
|
+
if (error instanceof WasmError) {
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
throw new WasmError(
|
|
388
|
+
`Call error: ${error instanceof Error ? error.message : String(error)}`,
|
|
389
|
+
methodPath
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Internal method to call server streaming WASM functions
|
|
395
|
+
*/
|
|
396
|
+
callStreamingMethod(methodPath, request, callback) {
|
|
397
|
+
this.ensureWASMLoaded();
|
|
398
|
+
try {
|
|
399
|
+
const jsonReq = JSON.parse(JSON.stringify(request));
|
|
400
|
+
const wasmMethod = this.getWasmMethod(methodPath);
|
|
401
|
+
const wrappedCallback = (responseStr, error, done) => {
|
|
402
|
+
let response = null;
|
|
403
|
+
if (responseStr && !error) {
|
|
404
|
+
try {
|
|
405
|
+
response = JSON.parse(responseStr);
|
|
406
|
+
} catch (e) {
|
|
407
|
+
response = responseStr;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return callback(response, error, done);
|
|
411
|
+
};
|
|
412
|
+
const wasmResponse = wasmMethod(JSON.stringify(jsonReq), wrappedCallback);
|
|
413
|
+
if (!wasmResponse.success) {
|
|
414
|
+
throw new WasmError(wasmResponse.message, methodPath);
|
|
415
|
+
}
|
|
416
|
+
} catch (error) {
|
|
417
|
+
if (error instanceof WasmError) {
|
|
418
|
+
throw error;
|
|
419
|
+
}
|
|
420
|
+
throw new WasmError(
|
|
421
|
+
`Streaming call error: ${error instanceof Error ? error.message : String(error)}`,
|
|
422
|
+
methodPath
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Ensure WASM module is loaded (synchronous version for service calls)
|
|
428
|
+
*/
|
|
429
|
+
ensureWASMLoaded() {
|
|
430
|
+
if (!this.isReady()) {
|
|
431
|
+
throw new Error("WASM module not loaded. Call loadWasm() and waitUntilReady() first.");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Load the WASM module asynchronously
|
|
436
|
+
*/
|
|
437
|
+
async loadWasm(wasmPath) {
|
|
438
|
+
if (this.wasmLoadPromise) {
|
|
439
|
+
return this.wasmLoadPromise;
|
|
440
|
+
}
|
|
441
|
+
this.wasmLoadPromise = this.loadWASMModule(wasmPath);
|
|
442
|
+
return this.wasmLoadPromise;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// src/client/wasm-bundle.ts
|
|
447
|
+
var WASMBundle = class {
|
|
448
|
+
constructor(config) {
|
|
449
|
+
this.wasm = null;
|
|
450
|
+
this.wasmLoadPromise = null;
|
|
451
|
+
this.browserServiceManager = null;
|
|
452
|
+
this.config = config;
|
|
453
|
+
this.browserServiceManager = new BrowserServiceManager();
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Register a browser service implementation
|
|
457
|
+
*/
|
|
458
|
+
registerBrowserService(name, implementation) {
|
|
459
|
+
if (!this.browserServiceManager) {
|
|
460
|
+
throw new Error("Browser service manager not initialized");
|
|
461
|
+
}
|
|
462
|
+
this.browserServiceManager.registerService(name, implementation);
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Check if WASM is ready for operations
|
|
466
|
+
*/
|
|
467
|
+
isReady() {
|
|
468
|
+
return this.wasm !== null && this.wasm !== void 0;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Wait for WASM to be ready (use during initialization)
|
|
472
|
+
*/
|
|
473
|
+
async waitUntilReady() {
|
|
474
|
+
if (!this.wasmLoadPromise) {
|
|
475
|
+
throw new Error("WASM loading not started. Call loadWasm() first.");
|
|
476
|
+
}
|
|
477
|
+
await this.wasmLoadPromise;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Load the WASM module asynchronously (singleton pattern)
|
|
481
|
+
*/
|
|
482
|
+
async loadWasm(wasmPath) {
|
|
483
|
+
if (this.wasmLoadPromise) {
|
|
484
|
+
return this.wasmLoadPromise;
|
|
485
|
+
}
|
|
486
|
+
this.wasmLoadPromise = this.loadWASMModule(wasmPath);
|
|
487
|
+
return this.wasmLoadPromise;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Get WASM method function by path
|
|
491
|
+
*/
|
|
492
|
+
getWasmMethod(methodPath) {
|
|
493
|
+
this.ensureWASMLoaded();
|
|
494
|
+
switch (this.config.apiStructure) {
|
|
495
|
+
case "namespaced":
|
|
496
|
+
const parts = methodPath.split(".");
|
|
497
|
+
let current = this.wasm;
|
|
498
|
+
for (const part of parts) {
|
|
499
|
+
current = current[part];
|
|
500
|
+
if (!current) {
|
|
501
|
+
throw new Error(`Method not found: ${methodPath}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return current;
|
|
505
|
+
case "flat":
|
|
506
|
+
const method = this.wasm[methodPath];
|
|
507
|
+
if (!method) {
|
|
508
|
+
throw new Error(`Method not found: ${methodPath}`);
|
|
509
|
+
}
|
|
510
|
+
return method;
|
|
511
|
+
case "service_based":
|
|
512
|
+
const serviceParts = methodPath.split(".");
|
|
513
|
+
let serviceCurrent = this.wasm;
|
|
514
|
+
for (const part of serviceParts) {
|
|
515
|
+
serviceCurrent = serviceCurrent[part];
|
|
516
|
+
if (!serviceCurrent) {
|
|
517
|
+
throw new Error(`Method not found: ${methodPath}`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return serviceCurrent;
|
|
521
|
+
default:
|
|
522
|
+
throw new Error(`Unsupported API structure: ${this.config.apiStructure}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Internal method to call WASM functions with JSON conversion
|
|
527
|
+
*/
|
|
528
|
+
callMethod(methodPath, request) {
|
|
529
|
+
try {
|
|
530
|
+
const jsonReq = JSON.parse(JSON.stringify(request));
|
|
531
|
+
const wasmMethod = this.getWasmMethod(methodPath);
|
|
532
|
+
const wasmResponse = wasmMethod(JSON.stringify(jsonReq));
|
|
533
|
+
if (!wasmResponse.success) {
|
|
534
|
+
throw new WasmError(wasmResponse.message, methodPath);
|
|
535
|
+
}
|
|
536
|
+
return wasmResponse.data;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
if (error instanceof WasmError) {
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
throw new WasmError(
|
|
542
|
+
`Call error: ${error instanceof Error ? error.message : String(error)}`,
|
|
543
|
+
methodPath
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Internal method to call async WASM functions with callback
|
|
549
|
+
*/
|
|
550
|
+
callMethodWithCallback(methodPath, request, callback) {
|
|
551
|
+
try {
|
|
552
|
+
const jsonReq = JSON.parse(JSON.stringify(request));
|
|
553
|
+
const wasmMethod = this.getWasmMethod(methodPath);
|
|
554
|
+
const wasmResponse = wasmMethod(JSON.stringify(jsonReq), callback);
|
|
555
|
+
if (!wasmResponse.success) {
|
|
556
|
+
throw new WasmError(wasmResponse.message, methodPath);
|
|
557
|
+
}
|
|
558
|
+
return Promise.resolve();
|
|
559
|
+
} catch (error) {
|
|
560
|
+
if (error instanceof WasmError) {
|
|
561
|
+
throw error;
|
|
562
|
+
}
|
|
563
|
+
throw new WasmError(
|
|
564
|
+
`Call error: ${error instanceof Error ? error.message : String(error)}`,
|
|
565
|
+
methodPath
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Internal method to call server streaming WASM functions
|
|
571
|
+
*/
|
|
572
|
+
callStreamingMethod(methodPath, request, callback) {
|
|
573
|
+
try {
|
|
574
|
+
const jsonReq = JSON.parse(JSON.stringify(request));
|
|
575
|
+
const wasmMethod = this.getWasmMethod(methodPath);
|
|
576
|
+
const wrappedCallback = (responseStr, error, done) => {
|
|
577
|
+
let response = null;
|
|
578
|
+
if (responseStr && !error) {
|
|
579
|
+
try {
|
|
580
|
+
response = JSON.parse(responseStr);
|
|
581
|
+
} catch (e) {
|
|
582
|
+
response = responseStr;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return callback(response, error, done);
|
|
586
|
+
};
|
|
587
|
+
const wasmResponse = wasmMethod(JSON.stringify(jsonReq), wrappedCallback);
|
|
588
|
+
if (!wasmResponse.success) {
|
|
589
|
+
throw new WasmError(wasmResponse.message, methodPath);
|
|
590
|
+
}
|
|
591
|
+
} catch (error) {
|
|
592
|
+
if (error instanceof WasmError) {
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
throw new WasmError(
|
|
596
|
+
`Streaming call error: ${error instanceof Error ? error.message : String(error)}`,
|
|
597
|
+
methodPath
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Ensure WASM module is loaded (synchronous version for service calls)
|
|
603
|
+
*/
|
|
604
|
+
ensureWASMLoaded() {
|
|
605
|
+
if (!this.isReady()) {
|
|
606
|
+
throw new Error("WASM module not loaded. Call loadWasm() and waitUntilReady() first.");
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Load the WASM module implementation
|
|
611
|
+
*/
|
|
612
|
+
async loadWASMModule(wasmPath) {
|
|
613
|
+
console.log(`Loading ${this.config.moduleName} WASM module...`);
|
|
614
|
+
if (this.checkIfPreLoaded()) {
|
|
615
|
+
console.log("WASM module already loaded (pre-loaded in test environment)");
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (!window.Go) {
|
|
619
|
+
const script = document.createElement("script");
|
|
620
|
+
script.src = "/wasm_exec.js";
|
|
621
|
+
document.head.appendChild(script);
|
|
622
|
+
await new Promise((resolve, reject) => {
|
|
623
|
+
script.onload = () => resolve();
|
|
624
|
+
script.onerror = () => reject(new Error("Failed to load wasm_exec.js"));
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
const go = new window.Go();
|
|
628
|
+
const wasmModule = await WebAssembly.instantiateStreaming(
|
|
629
|
+
fetch(wasmPath),
|
|
630
|
+
go.importObject
|
|
631
|
+
);
|
|
632
|
+
go.run(wasmModule.instance);
|
|
633
|
+
if (this.browserServiceManager) {
|
|
634
|
+
this.browserServiceManager.setWasmModule(window);
|
|
635
|
+
this.browserServiceManager.startProcessing();
|
|
636
|
+
}
|
|
637
|
+
this.verifyWASMLoaded();
|
|
638
|
+
console.log(`${this.config.moduleName} WASM module loaded successfully`);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Check if WASM is pre-loaded (for testing)
|
|
642
|
+
*/
|
|
643
|
+
checkIfPreLoaded() {
|
|
644
|
+
switch (this.config.apiStructure) {
|
|
645
|
+
case "namespaced":
|
|
646
|
+
if (window[this.config.jsNamespace]) {
|
|
647
|
+
this.wasm = window[this.config.jsNamespace];
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
return false;
|
|
651
|
+
case "flat":
|
|
652
|
+
if (window[this.config.jsNamespace + "LoadUserData"]) {
|
|
653
|
+
this.wasm = window;
|
|
654
|
+
return true;
|
|
655
|
+
}
|
|
656
|
+
return false;
|
|
657
|
+
case "service_based":
|
|
658
|
+
if (window.services) {
|
|
659
|
+
this.wasm = window.services;
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
return false;
|
|
663
|
+
default:
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Verify WASM APIs are available after loading
|
|
669
|
+
*/
|
|
670
|
+
verifyWASMLoaded() {
|
|
671
|
+
switch (this.config.apiStructure) {
|
|
672
|
+
case "namespaced":
|
|
673
|
+
if (!window[this.config.jsNamespace]) {
|
|
674
|
+
throw new Error("WASM APIs not found - module may not have loaded correctly");
|
|
675
|
+
}
|
|
676
|
+
this.wasm = window[this.config.jsNamespace];
|
|
677
|
+
break;
|
|
678
|
+
case "flat":
|
|
679
|
+
if (!window[this.config.jsNamespace + "LoadUserData"]) {
|
|
680
|
+
throw new Error("WASM APIs not found - module may not have loaded correctly");
|
|
681
|
+
}
|
|
682
|
+
this.wasm = window;
|
|
683
|
+
break;
|
|
684
|
+
case "service_based":
|
|
685
|
+
if (!window.services) {
|
|
686
|
+
throw new Error("WASM APIs not found - module may not have loaded correctly");
|
|
687
|
+
}
|
|
688
|
+
this.wasm = window.services;
|
|
689
|
+
break;
|
|
690
|
+
default:
|
|
691
|
+
throw new Error(`Unsupported API structure: ${this.config.apiStructure}`);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// src/client/service-client.ts
|
|
697
|
+
var ServiceClient = class {
|
|
698
|
+
constructor(bundle) {
|
|
699
|
+
this.bundle = bundle;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Check if the underlying WASM bundle is ready
|
|
703
|
+
*/
|
|
704
|
+
isReady() {
|
|
705
|
+
return this.bundle.isReady();
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Wait for the underlying WASM bundle to be ready
|
|
709
|
+
*/
|
|
710
|
+
async waitUntilReady() {
|
|
711
|
+
return this.bundle.waitUntilReady();
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Call a synchronous WASM method
|
|
715
|
+
*/
|
|
716
|
+
callMethod(methodPath, request) {
|
|
717
|
+
return this.bundle.callMethod(methodPath, request);
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Call an asynchronous WASM method with callback
|
|
721
|
+
*/
|
|
722
|
+
callMethodWithCallback(methodPath, request, callback) {
|
|
723
|
+
return this.bundle.callMethodWithCallback(methodPath, request, callback);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Call a server streaming WASM method
|
|
727
|
+
*/
|
|
728
|
+
callStreamingMethod(methodPath, request, callback) {
|
|
729
|
+
return this.bundle.callStreamingMethod(methodPath, request, callback);
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
// src/types/patches.ts
|
|
734
|
+
var PatchOperation = /* @__PURE__ */ ((PatchOperation2) => {
|
|
735
|
+
PatchOperation2["SET"] = "SET";
|
|
736
|
+
PatchOperation2["INSERT_LIST"] = "INSERT_LIST";
|
|
737
|
+
PatchOperation2["REMOVE_LIST"] = "REMOVE_LIST";
|
|
738
|
+
PatchOperation2["MOVE_LIST"] = "MOVE_LIST";
|
|
739
|
+
PatchOperation2["INSERT_MAP"] = "INSERT_MAP";
|
|
740
|
+
PatchOperation2["REMOVE_MAP"] = "REMOVE_MAP";
|
|
741
|
+
PatchOperation2["CLEAR_LIST"] = "CLEAR_LIST";
|
|
742
|
+
PatchOperation2["CLEAR_MAP"] = "CLEAR_MAP";
|
|
743
|
+
return PatchOperation2;
|
|
744
|
+
})(PatchOperation || {});
|
|
745
|
+
var PatchSource = /* @__PURE__ */ ((PatchSource2) => {
|
|
746
|
+
PatchSource2["LOCAL"] = "LOCAL";
|
|
747
|
+
PatchSource2["REMOTE"] = "REMOTE";
|
|
748
|
+
PatchSource2["SERVER"] = "SERVER";
|
|
749
|
+
PatchSource2["STORAGE"] = "STORAGE";
|
|
750
|
+
return PatchSource2;
|
|
751
|
+
})(PatchSource || {});
|
|
752
|
+
|
|
753
|
+
exports.BaseDeserializer = BaseDeserializer;
|
|
754
|
+
exports.BaseSchemaRegistry = BaseSchemaRegistry;
|
|
755
|
+
exports.BrowserServiceManager = BrowserServiceManager;
|
|
756
|
+
exports.FieldType = FieldType;
|
|
757
|
+
exports.PatchOperation = PatchOperation;
|
|
758
|
+
exports.PatchSource = PatchSource;
|
|
759
|
+
exports.ServiceClient = ServiceClient;
|
|
760
|
+
exports.WASMBundle = WASMBundle;
|
|
761
|
+
exports.WASMServiceClient = WASMServiceClient;
|
|
762
|
+
exports.WasmError = WasmError;
|
|
763
|
+
//# sourceMappingURL=index.js.map
|
|
764
|
+
//# sourceMappingURL=index.js.map
|