@mobileaidev/ai-app-bridge 0.2.15 → 0.3.0-rc.2
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 +201 -0
- package/NOTICE +7 -0
- package/README.md +306 -53
- package/bin/ai-app-bridge.js +51 -4504
- package/bin/android-permissions.js +152 -0
- package/bin/android-uia-xml.js +74 -0
- package/bin/artifact-paths.js +127 -1
- package/bin/bridge-forward.js +56 -0
- package/bin/command-discovery.js +86 -0
- package/bin/command-errors.js +60 -0
- package/bin/command-registry.js +504 -0
- package/bin/command-request.js +14 -0
- package/bin/command-router.js +80 -0
- package/bin/connection-cache.js +119 -0
- package/bin/device-provider.js +2934 -0
- package/bin/execution-host.js +596 -0
- package/bin/execution-runtime.js +101 -0
- package/bin/fact-codec.js +321 -0
- package/bin/fact-recorder.js +691 -0
- package/bin/fact-store.js +226 -0
- package/bin/feedback-probe.js +285 -0
- package/bin/intent/install-intent.js +267 -0
- package/bin/intent/intent-action-executor.js +129 -0
- package/bin/intent/intent-autonomous-adapter.js +46 -0
- package/bin/intent/intent-capture-port.js +64 -0
- package/bin/intent/intent-entry.js +226 -0
- package/bin/intent/intent-errors.js +28 -0
- package/bin/intent/intent-evidence-store.js +121 -0
- package/bin/intent/intent-lifetime.js +62 -0
- package/bin/intent/intent-observation-target.js +33 -0
- package/bin/intent/intent-observer.js +194 -0
- package/bin/intent/intent-production-adapter.js +334 -0
- package/bin/intent/intent-provider.js +27 -0
- package/bin/intent/intent-runtime.js +63 -0
- package/bin/intent/intent-worker.js +432 -0
- package/bin/intent/ios-intent-adapter.js +90 -0
- package/bin/intent/permission-intent.js +239 -0
- package/bin/intent/web-intent-adapter.js +31 -0
- package/bin/ios-device-outcome.js +47 -0
- package/bin/ios-execution.js +108 -0
- package/bin/ios-provider.js +497 -583
- package/bin/ios-runtime-binding.js +54 -0
- package/bin/ios-wda-execution.js +70 -0
- package/bin/ios-wda-port.js +98 -0
- package/bin/ios-wda-project.js +79 -0
- package/bin/mcp-server.js +83 -1040
- package/bin/mmap-scan-index.js +329 -0
- package/bin/observation-collector.js +862 -0
- package/bin/runtime-client.js +154 -0
- package/bin/runtime-directory.js +107 -0
- package/bin/runtime-protocol.js +36 -0
- package/bin/script/bounded-script-registry.js +103 -0
- package/bin/script/node-runtime-adapter.js +233 -0
- package/bin/script/progress-projector.js +63 -0
- package/bin/script/python-runtime-adapter.js +111 -0
- package/bin/script/rolling-summary.js +134 -0
- package/bin/script/script-agent-port.js +40 -0
- package/bin/script/script-assert.js +95 -0
- package/bin/script/script-capture-port.js +76 -0
- package/bin/script/script-catalog.js +85 -0
- package/bin/script/script-durable-restore.js +195 -0
- package/bin/script/script-entry-code.js +26 -0
- package/bin/script/script-entry-route.js +38 -0
- package/bin/script/script-entry.js +3 -0
- package/bin/script/script-errors.js +29 -0
- package/bin/script/script-evidence-store.js +22 -0
- package/bin/script/script-format-removed.js +26 -0
- package/bin/script/script-host-port.js +397 -0
- package/bin/script/script-ledger.js +64 -0
- package/bin/script/script-result.js +57 -0
- package/bin/script/script-sdk.js +152 -0
- package/bin/script/script-sdk.py +153 -0
- package/bin/script/script-session-channel.js +127 -0
- package/bin/script/script-spec.js +86 -0
- package/bin/script/script-supervisor.js +919 -0
- package/bin/script/templates/checkpoint-reentry.js +13 -0
- package/bin/segment-index.js +481 -0
- package/bin/segmented-fact-store.js +1571 -0
- package/bin/shared-kernel/android-h5-target.js +10 -0
- package/bin/shared-kernel/android-install-execution.js +176 -0
- package/bin/shared-kernel/android-sdk-endpoint.js +42 -0
- package/bin/shared-kernel/android-shell-execution.js +195 -0
- package/bin/shared-kernel/argument-schema.js +117 -0
- package/bin/shared-kernel/canonical-path.js +17 -0
- package/bin/shared-kernel/device-acknowledgements.js +53 -0
- package/bin/shared-kernel/device-completion-history.js +52 -0
- package/bin/shared-kernel/device-mutation-lease.js +219 -0
- package/bin/shared-kernel/device-ownership-recovery.js +95 -0
- package/bin/shared-kernel/device-ownership-store.js +94 -0
- package/bin/shared-kernel/evidence-adapters.js +251 -0
- package/bin/shared-kernel/evidence-archive.js +329 -0
- package/bin/shared-kernel/evidence-recording.js +131 -0
- package/bin/shared-kernel/evidence-schema.js +194 -0
- package/bin/shared-kernel/evidence-store.js +190 -0
- package/bin/shared-kernel/execution-admission.js +22 -0
- package/bin/shared-kernel/execution-contracts.js +171 -0
- package/bin/shared-kernel/execution-io.js +106 -0
- package/bin/shared-kernel/execution-ledger.js +125 -0
- package/bin/shared-kernel/execution-scope.js +87 -0
- package/bin/shared-kernel/execution-target.js +115 -0
- package/bin/shared-kernel/flutter-execution.js +13 -0
- package/bin/shared-kernel/flutter-h5-port.js +60 -0
- package/bin/shared-kernel/flutter-h5-target.js +9 -0
- package/bin/shared-kernel/flutter-target.js +75 -0
- package/bin/shared-kernel/h5-execution.js +11 -0
- package/bin/shared-kernel/h5-target.js +31 -0
- package/bin/shared-kernel/host-fact-store.js +49 -0
- package/bin/shared-kernel/ios-h5-target.js +9 -0
- package/bin/shared-kernel/ios-native-target.js +71 -0
- package/bin/shared-kernel/live-capture-query.js +115 -0
- package/bin/shared-kernel/managed-sdk-execution.js +78 -0
- package/bin/shared-kernel/native-execution.js +13 -0
- package/bin/shared-kernel/native-target.js +156 -0
- package/bin/shared-kernel/provider-command-contracts.js +55 -0
- package/bin/shared-kernel/recorded-payload-archive.js +195 -0
- package/bin/shared-kernel/request-context.js +35 -0
- package/bin/shared-kernel/semantic-node.js +55 -0
- package/bin/shared-kernel/summary-transformer.js +352 -0
- package/bin/shared-kernel/target-lease-protocol.js +47 -0
- package/bin/shared-kernel/text-wait.js +111 -0
- package/bin/shared-kernel/uia-execution.js +96 -0
- package/bin/shared-kernel/uia-protocol.js +214 -0
- package/bin/shared-kernel/uia-runtime-port.js +377 -0
- package/bin/shared-kernel/uia-target.js +39 -0
- package/bin/shared-kernel/web-dom-target.js +44 -0
- package/bin/shared-kernel/xml-attributes.js +25 -0
- package/bin/target-execution.js +275 -0
- package/bin/web/command-schema.js +60 -0
- package/bin/web/session-store.js +157 -0
- package/bin/web-provider.js +334 -553
- package/docs/COMMAND_CONTRACT.md +1563 -0
- package/docs/EVIDENCE_ARCHIVE.md +214 -0
- package/docs/INTENT_FOREGROUND.md +71 -0
- package/docs/INTENT_NATIVE_EDITING.md +79 -0
- package/docs/RELEASE.md +59 -0
- package/docs/SCRIPT_AUTHORING.md +489 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/LICENSE +201 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/NOTICE +7 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/binding.gyp +36 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/bindings/node/sfs_node.c +597 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/include/sfs.h +178 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/index.js +5 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/package.json +24 -0
- package/node_modules/@mobileaidev/segmented-fact-store-native/src/sfs.c +2349 -0
- package/package.json +60 -5
- package/runtime/ios-wda/AABWDABinding.h +19 -0
- package/runtime/ios-wda/AABWDABinding.m +97 -0
- package/runtime/ios-wda/AABWDAExecution.h +26 -0
- package/runtime/ios-wda/AABWDAExecution.m +172 -0
- package/runtime/ios-wda/AABWDAIntegration.h +71 -0
- package/runtime/ios-wda/AABWDAManagedRoutes.h +392 -0
- package/runtime/ios-wda/AABWDAReceiptStore.h +10 -0
- package/runtime/ios-wda/AABWDAReceiptStore.m +116 -0
- package/runtime/uia/ai-app-bridge-uia.jar +0 -0
- package/runtime/uia/manifest.json +22 -0
- package/skills/ai-app-bridge-use/SKILL.md +23 -360
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
#include <node_api.h>
|
|
2
|
+
|
|
3
|
+
#include "sfs.h"
|
|
4
|
+
|
|
5
|
+
#include <stdbool.h>
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
typedef struct node_sfs_handle {
|
|
12
|
+
sfs_store_t *store;
|
|
13
|
+
} node_sfs_handle_t;
|
|
14
|
+
|
|
15
|
+
static napi_value js_undefined(napi_env env)
|
|
16
|
+
{
|
|
17
|
+
napi_value value;
|
|
18
|
+
(void)napi_get_undefined(env, &value);
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static void throw_napi(napi_env env, const char *message)
|
|
23
|
+
{
|
|
24
|
+
(void)napi_throw_error(env, "napi_error", message);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static const char *result_code(sfs_result_t result)
|
|
28
|
+
{
|
|
29
|
+
switch (result) {
|
|
30
|
+
case SFS_ERR_INVALID_ARGUMENT: return "sfs_invalid_argument";
|
|
31
|
+
case SFS_ERR_IO: return "sfs_io";
|
|
32
|
+
case SFS_ERR_FORMAT_VERSION: return "sfs_format_version";
|
|
33
|
+
case SFS_ERR_CORRUPT: return "sfs_corrupt";
|
|
34
|
+
case SFS_ERR_FULL: return "sfs_full";
|
|
35
|
+
case SFS_ERR_BUSY: return "sfs_busy";
|
|
36
|
+
case SFS_ERR_NOMEM: return "sfs_nomem";
|
|
37
|
+
case SFS_ERR_CLOSED: return "sfs_closed";
|
|
38
|
+
case SFS_ERR_PARTITION_DISABLED: return "sfs_partition_disabled";
|
|
39
|
+
default: return "sfs_error";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static void throw_sfs(napi_env env, sfs_result_t result, const sfs_error_t *error)
|
|
44
|
+
{
|
|
45
|
+
char message[256];
|
|
46
|
+
const char *detail = error != NULL && error->message[0] != '\0'
|
|
47
|
+
? error->message
|
|
48
|
+
: "segmented fact store operation failed";
|
|
49
|
+
(void)snprintf(message,
|
|
50
|
+
sizeof(message),
|
|
51
|
+
"%s (result=%d system=%d)",
|
|
52
|
+
detail,
|
|
53
|
+
(int)result,
|
|
54
|
+
error != NULL ? error->system_code : 0);
|
|
55
|
+
(void)napi_throw_error(env, result_code(result), message);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static bool named_property(napi_env env,
|
|
59
|
+
napi_value object,
|
|
60
|
+
const char *name,
|
|
61
|
+
napi_value *out_value,
|
|
62
|
+
bool *out_present)
|
|
63
|
+
{
|
|
64
|
+
bool present = false;
|
|
65
|
+
if (napi_has_named_property(env, object, name, &present) != napi_ok) {
|
|
66
|
+
throw_napi(env, "failed to inspect option property");
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
*out_present = present;
|
|
70
|
+
if (!present) return true;
|
|
71
|
+
if (napi_get_named_property(env, object, name, out_value) != napi_ok) {
|
|
72
|
+
throw_napi(env, "failed to read option property");
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static bool value_uint64(napi_env env, napi_value value, uint64_t *out_value)
|
|
79
|
+
{
|
|
80
|
+
napi_valuetype type;
|
|
81
|
+
if (napi_typeof(env, value, &type) != napi_ok) {
|
|
82
|
+
throw_napi(env, "failed to inspect integer value");
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
if (type == napi_bigint) {
|
|
86
|
+
bool lossless = false;
|
|
87
|
+
if (napi_get_value_bigint_uint64(env, value, out_value, &lossless) != napi_ok || !lossless) {
|
|
88
|
+
throw_napi(env, "integer BigInt is outside uint64 range");
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (type == napi_number) {
|
|
94
|
+
double number = 0.0;
|
|
95
|
+
if (napi_get_value_double(env, value, &number) != napi_ok
|
|
96
|
+
|| number < 0.0
|
|
97
|
+
|| number > 9007199254740991.0) {
|
|
98
|
+
throw_napi(env, "integer must be a non-negative safe Number or BigInt");
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
*out_value = (uint64_t)number;
|
|
102
|
+
if ((double)*out_value != number) {
|
|
103
|
+
throw_napi(env, "integer Number must not contain a fractional part");
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
throw_napi(env, "integer must be a Number or BigInt");
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static bool optional_uint64(napi_env env,
|
|
113
|
+
napi_value object,
|
|
114
|
+
const char *name,
|
|
115
|
+
uint64_t fallback,
|
|
116
|
+
uint64_t *out_value)
|
|
117
|
+
{
|
|
118
|
+
napi_value value;
|
|
119
|
+
bool present;
|
|
120
|
+
if (!named_property(env, object, name, &value, &present)) return false;
|
|
121
|
+
if (!present) {
|
|
122
|
+
*out_value = fallback;
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return value_uint64(env, value, out_value);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static bool optional_uint32(napi_env env,
|
|
129
|
+
napi_value object,
|
|
130
|
+
const char *name,
|
|
131
|
+
uint32_t fallback,
|
|
132
|
+
uint32_t *out_value)
|
|
133
|
+
{
|
|
134
|
+
uint64_t value;
|
|
135
|
+
if (!optional_uint64(env, object, name, fallback, &value)) return false;
|
|
136
|
+
if (value > UINT32_MAX) {
|
|
137
|
+
throw_napi(env, "integer exceeds uint32 range");
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
*out_value = (uint32_t)value;
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static bool required_string(napi_env env,
|
|
145
|
+
napi_value object,
|
|
146
|
+
const char *name,
|
|
147
|
+
char **out_value)
|
|
148
|
+
{
|
|
149
|
+
napi_value value;
|
|
150
|
+
napi_valuetype type;
|
|
151
|
+
bool present;
|
|
152
|
+
size_t length = 0u;
|
|
153
|
+
char *buffer;
|
|
154
|
+
if (!named_property(env, object, name, &value, &present)) return false;
|
|
155
|
+
if (!present || napi_typeof(env, value, &type) != napi_ok || type != napi_string) {
|
|
156
|
+
throw_napi(env, "directory must be a non-empty string");
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
if (napi_get_value_string_utf8(env, value, NULL, 0u, &length) != napi_ok || length == 0u) {
|
|
160
|
+
throw_napi(env, "directory must be a non-empty string");
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
buffer = (char *)malloc(length + 1u);
|
|
164
|
+
if (buffer == NULL) {
|
|
165
|
+
throw_napi(env, "unable to allocate directory path");
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (napi_get_value_string_utf8(env, value, buffer, length + 1u, &length) != napi_ok) {
|
|
169
|
+
free(buffer);
|
|
170
|
+
throw_napi(env, "unable to decode directory path");
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
*out_value = buffer;
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
static node_sfs_handle_t *required_handle(napi_env env, napi_value value)
|
|
178
|
+
{
|
|
179
|
+
node_sfs_handle_t *handle = NULL;
|
|
180
|
+
if (napi_get_value_external(env, value, (void **)&handle) != napi_ok
|
|
181
|
+
|| handle == NULL
|
|
182
|
+
|| handle->store == NULL) {
|
|
183
|
+
throw_napi(env, "segmented fact store handle is closed or invalid");
|
|
184
|
+
return NULL;
|
|
185
|
+
}
|
|
186
|
+
return handle;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static void finalize_handle(napi_env env, void *data, void *hint)
|
|
190
|
+
{
|
|
191
|
+
node_sfs_handle_t *handle = (node_sfs_handle_t *)data;
|
|
192
|
+
sfs_error_t error;
|
|
193
|
+
(void)env;
|
|
194
|
+
(void)hint;
|
|
195
|
+
if (handle == NULL) return;
|
|
196
|
+
if (handle->store != NULL) {
|
|
197
|
+
(void)sfs_close(handle->store, &error);
|
|
198
|
+
handle->store = NULL;
|
|
199
|
+
}
|
|
200
|
+
free(handle);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static napi_value uint64_value(napi_env env, uint64_t value)
|
|
204
|
+
{
|
|
205
|
+
napi_value result;
|
|
206
|
+
if (napi_create_bigint_uint64(env, value, &result) != napi_ok) return js_undefined(env);
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static void set_named(napi_env env, napi_value object, const char *name, napi_value value)
|
|
211
|
+
{
|
|
212
|
+
(void)napi_set_named_property(env, object, name, value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static void set_uint32(napi_env env, napi_value object, const char *name, uint32_t value)
|
|
216
|
+
{
|
|
217
|
+
napi_value result;
|
|
218
|
+
if (napi_create_uint32(env, value, &result) == napi_ok) set_named(env, object, name, result);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
static void set_uint64(napi_env env, napi_value object, const char *name, uint64_t value)
|
|
222
|
+
{
|
|
223
|
+
set_named(env, object, name, uint64_value(env, value));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
static void set_boolean(napi_env env, napi_value object, const char *name, bool value)
|
|
227
|
+
{
|
|
228
|
+
napi_value result;
|
|
229
|
+
if (napi_get_boolean(env, value, &result) == napi_ok) set_named(env, object, name, result);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static napi_value record_info_value(napi_env env, const sfs_record_info_t *info)
|
|
233
|
+
{
|
|
234
|
+
napi_value object;
|
|
235
|
+
(void)napi_create_object(env, &object);
|
|
236
|
+
set_uint32(env, object, "payloadLength", info->payload_length);
|
|
237
|
+
set_uint32(env, object, "partitionId", info->partition_id);
|
|
238
|
+
set_uint32(env, object, "flags", info->flags);
|
|
239
|
+
set_uint64(env, object, "sequence", info->sequence);
|
|
240
|
+
set_uint64(env, object, "segmentId", info->segment_id);
|
|
241
|
+
set_uint64(env, object, "frameOffset", info->frame_offset);
|
|
242
|
+
set_uint64(env, object, "gapFirstSequence", info->gap_first_sequence);
|
|
243
|
+
set_uint64(env, object, "gapLastSequence", info->gap_last_sequence);
|
|
244
|
+
return object;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
static napi_value cursor_value(napi_env env, const sfs_cursor_t *cursor)
|
|
248
|
+
{
|
|
249
|
+
napi_value object;
|
|
250
|
+
(void)napi_create_object(env, &object);
|
|
251
|
+
set_uint32(env, object, "partitionId", cursor->partition_id);
|
|
252
|
+
set_uint32(env, object, "flags", cursor->flags);
|
|
253
|
+
set_uint64(env, object, "afterSequence", cursor->after_sequence);
|
|
254
|
+
set_uint64(env, object, "segmentId", cursor->segment_id);
|
|
255
|
+
set_uint64(env, object, "offset", cursor->offset);
|
|
256
|
+
return object;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
static bool parse_cursor(napi_env env, napi_value value, sfs_cursor_t *cursor)
|
|
260
|
+
{
|
|
261
|
+
napi_valuetype type;
|
|
262
|
+
if (napi_typeof(env, value, &type) != napi_ok || type != napi_object) {
|
|
263
|
+
throw_napi(env, "cursor must be an object");
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
memset(cursor, 0, sizeof(*cursor));
|
|
267
|
+
if (!optional_uint32(env, value, "partitionId", SFS_PARTITION_ALL, &cursor->partition_id)) return false;
|
|
268
|
+
if (!optional_uint32(env, value, "flags", 0u, &cursor->flags)) return false;
|
|
269
|
+
if (!optional_uint64(env, value, "afterSequence", 0u, &cursor->after_sequence)) return false;
|
|
270
|
+
if (!optional_uint64(env, value, "segmentId", 0u, &cursor->segment_id)) return false;
|
|
271
|
+
if (!optional_uint64(env, value, "offset", 0u, &cursor->offset)) return false;
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static napi_value binding_open(napi_env env, napi_callback_info info)
|
|
276
|
+
{
|
|
277
|
+
napi_value argv[1];
|
|
278
|
+
size_t argc = 1u;
|
|
279
|
+
napi_valuetype type;
|
|
280
|
+
sfs_open_options_t options;
|
|
281
|
+
sfs_error_t error;
|
|
282
|
+
sfs_result_t result;
|
|
283
|
+
sfs_store_t *store = NULL;
|
|
284
|
+
node_sfs_handle_t *handle;
|
|
285
|
+
napi_value external;
|
|
286
|
+
napi_value quotas;
|
|
287
|
+
bool quotas_present;
|
|
288
|
+
bool is_array = false;
|
|
289
|
+
uint32_t length = 0u;
|
|
290
|
+
char *directory = NULL;
|
|
291
|
+
|
|
292
|
+
if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL) != napi_ok
|
|
293
|
+
|| argc != 1u
|
|
294
|
+
|| napi_typeof(env, argv[0], &type) != napi_ok
|
|
295
|
+
|| type != napi_object) {
|
|
296
|
+
throw_napi(env, "open(options) requires an object");
|
|
297
|
+
return NULL;
|
|
298
|
+
}
|
|
299
|
+
memset(&options, 0, sizeof(options));
|
|
300
|
+
options.struct_size = sizeof(options);
|
|
301
|
+
options.flags = SFS_OPEN_CREATE;
|
|
302
|
+
options.segment_size = SFS_DEFAULT_SEGMENT_SIZE;
|
|
303
|
+
if (!required_string(env, argv[0], "directory", &directory)) return NULL;
|
|
304
|
+
options.directory = directory;
|
|
305
|
+
if (!optional_uint64(env, argv[0], "segmentSize", options.segment_size, &options.segment_size)) {
|
|
306
|
+
free(directory);
|
|
307
|
+
return NULL;
|
|
308
|
+
}
|
|
309
|
+
if (!named_property(env, argv[0], "partitionQuotas", "as, "as_present)) {
|
|
310
|
+
free(directory);
|
|
311
|
+
return NULL;
|
|
312
|
+
}
|
|
313
|
+
if (quotas_present) {
|
|
314
|
+
if (napi_is_array(env, quotas, &is_array) != napi_ok || !is_array
|
|
315
|
+
|| napi_get_array_length(env, quotas, &length) != napi_ok
|
|
316
|
+
|| length > SFS_MAX_PARTITIONS) {
|
|
317
|
+
free(directory);
|
|
318
|
+
throw_napi(env, "partitionQuotas must be an array with at most eight entries");
|
|
319
|
+
return NULL;
|
|
320
|
+
}
|
|
321
|
+
for (uint32_t index = 0u; index < length; index += 1u) {
|
|
322
|
+
napi_value value;
|
|
323
|
+
if (napi_get_element(env, quotas, index, &value) != napi_ok
|
|
324
|
+
|| !value_uint64(env, value, &options.partition_quotas[index])) {
|
|
325
|
+
free(directory);
|
|
326
|
+
return NULL;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
result = sfs_open(&options, &store, &error);
|
|
331
|
+
free(directory);
|
|
332
|
+
if (result != SFS_OK) {
|
|
333
|
+
throw_sfs(env, result, &error);
|
|
334
|
+
return NULL;
|
|
335
|
+
}
|
|
336
|
+
handle = (node_sfs_handle_t *)calloc(1u, sizeof(*handle));
|
|
337
|
+
if (handle == NULL) {
|
|
338
|
+
(void)sfs_close(store, &error);
|
|
339
|
+
throw_napi(env, "unable to allocate native handle");
|
|
340
|
+
return NULL;
|
|
341
|
+
}
|
|
342
|
+
handle->store = store;
|
|
343
|
+
if (napi_create_external(env, handle, finalize_handle, NULL, &external) != napi_ok) {
|
|
344
|
+
finalize_handle(env, handle, NULL);
|
|
345
|
+
throw_napi(env, "unable to create native handle");
|
|
346
|
+
return NULL;
|
|
347
|
+
}
|
|
348
|
+
return external;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static napi_value binding_append(napi_env env, napi_callback_info info)
|
|
352
|
+
{
|
|
353
|
+
napi_value argv[4];
|
|
354
|
+
size_t argc = 4u;
|
|
355
|
+
node_sfs_handle_t *handle;
|
|
356
|
+
uint64_t partition_value;
|
|
357
|
+
bool is_buffer = false;
|
|
358
|
+
void *payload = NULL;
|
|
359
|
+
size_t payload_length = 0u;
|
|
360
|
+
bool sync = false;
|
|
361
|
+
sfs_record_info_t record;
|
|
362
|
+
sfs_error_t error;
|
|
363
|
+
sfs_result_t result;
|
|
364
|
+
|
|
365
|
+
if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL) != napi_ok || argc < 3u) {
|
|
366
|
+
throw_napi(env, "append(handle, partitionId, buffer, sync?) requires three arguments");
|
|
367
|
+
return NULL;
|
|
368
|
+
}
|
|
369
|
+
handle = required_handle(env, argv[0]);
|
|
370
|
+
if (handle == NULL || !value_uint64(env, argv[1], &partition_value)) return NULL;
|
|
371
|
+
if (partition_value >= SFS_MAX_PARTITIONS) {
|
|
372
|
+
throw_napi(env, "partitionId must be between 0 and 7");
|
|
373
|
+
return NULL;
|
|
374
|
+
}
|
|
375
|
+
if (napi_is_buffer(env, argv[2], &is_buffer) != napi_ok || !is_buffer
|
|
376
|
+
|| napi_get_buffer_info(env, argv[2], &payload, &payload_length) != napi_ok
|
|
377
|
+
|| payload_length > UINT32_MAX) {
|
|
378
|
+
throw_napi(env, "payload must be a Buffer no larger than uint32");
|
|
379
|
+
return NULL;
|
|
380
|
+
}
|
|
381
|
+
if (argc >= 4u && napi_get_value_bool(env, argv[3], &sync) != napi_ok) {
|
|
382
|
+
throw_napi(env, "sync must be a boolean");
|
|
383
|
+
return NULL;
|
|
384
|
+
}
|
|
385
|
+
memset(&record, 0, sizeof(record));
|
|
386
|
+
record.struct_size = sizeof(record);
|
|
387
|
+
result = sfs_append(handle->store,
|
|
388
|
+
(uint32_t)partition_value,
|
|
389
|
+
payload,
|
|
390
|
+
(uint32_t)payload_length,
|
|
391
|
+
sync ? SFS_DURABILITY_SYNC : SFS_DURABILITY_MEMORY,
|
|
392
|
+
&record,
|
|
393
|
+
&error);
|
|
394
|
+
if (result != SFS_OK) {
|
|
395
|
+
throw_sfs(env, result, &error);
|
|
396
|
+
return NULL;
|
|
397
|
+
}
|
|
398
|
+
return record_info_value(env, &record);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
static napi_value binding_scan(napi_env env, napi_callback_info info)
|
|
402
|
+
{
|
|
403
|
+
napi_value argv[2];
|
|
404
|
+
size_t argc = 2u;
|
|
405
|
+
node_sfs_handle_t *handle;
|
|
406
|
+
sfs_cursor_t cursor;
|
|
407
|
+
sfs_record_info_t record;
|
|
408
|
+
sfs_error_t error;
|
|
409
|
+
sfs_result_t result;
|
|
410
|
+
napi_value object;
|
|
411
|
+
napi_value payload;
|
|
412
|
+
void *buffer = NULL;
|
|
413
|
+
uint32_t required_length = 0u;
|
|
414
|
+
|
|
415
|
+
if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL) != napi_ok || argc != 2u) {
|
|
416
|
+
throw_napi(env, "scan(handle, cursor) requires two arguments");
|
|
417
|
+
return NULL;
|
|
418
|
+
}
|
|
419
|
+
handle = required_handle(env, argv[0]);
|
|
420
|
+
if (handle == NULL || !parse_cursor(env, argv[1], &cursor)) return NULL;
|
|
421
|
+
memset(&record, 0, sizeof(record));
|
|
422
|
+
record.struct_size = sizeof(record);
|
|
423
|
+
result = sfs_scan(handle->store, &cursor, NULL, 0u, &record, &error);
|
|
424
|
+
if (result == SFS_END) {
|
|
425
|
+
(void)napi_create_object(env, &object);
|
|
426
|
+
set_boolean(env, object, "done", true);
|
|
427
|
+
set_named(env, object, "cursor", cursor_value(env, &cursor));
|
|
428
|
+
return object;
|
|
429
|
+
}
|
|
430
|
+
if (result != SFS_BUFFER_TOO_SMALL && result != SFS_OK) {
|
|
431
|
+
throw_sfs(env, result, &error);
|
|
432
|
+
return NULL;
|
|
433
|
+
}
|
|
434
|
+
required_length = record.payload_length;
|
|
435
|
+
if (required_length > 0u) {
|
|
436
|
+
if (napi_create_buffer(env, required_length, &buffer, &payload) != napi_ok) {
|
|
437
|
+
throw_napi(env, "unable to allocate scan buffer");
|
|
438
|
+
return NULL;
|
|
439
|
+
}
|
|
440
|
+
memset(&record, 0, sizeof(record));
|
|
441
|
+
record.struct_size = sizeof(record);
|
|
442
|
+
result = sfs_scan(handle->store,
|
|
443
|
+
&cursor,
|
|
444
|
+
buffer,
|
|
445
|
+
required_length,
|
|
446
|
+
&record,
|
|
447
|
+
&error);
|
|
448
|
+
if (result != SFS_OK) {
|
|
449
|
+
throw_sfs(env, result, &error);
|
|
450
|
+
return NULL;
|
|
451
|
+
}
|
|
452
|
+
} else {
|
|
453
|
+
if (napi_create_buffer(env, 0u, &buffer, &payload) != napi_ok) {
|
|
454
|
+
throw_napi(env, "unable to create empty scan buffer");
|
|
455
|
+
return NULL;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
(void)napi_create_object(env, &object);
|
|
459
|
+
set_boolean(env, object, "done", false);
|
|
460
|
+
set_named(env, object, "payload", payload);
|
|
461
|
+
set_named(env, object, "record", record_info_value(env, &record));
|
|
462
|
+
set_named(env, object, "cursor", cursor_value(env, &cursor));
|
|
463
|
+
return object;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
static napi_value partition_status_value(napi_env env, const sfs_partition_status_t *status)
|
|
467
|
+
{
|
|
468
|
+
napi_value object;
|
|
469
|
+
(void)napi_create_object(env, &object);
|
|
470
|
+
set_uint32(env, object, "partitionId", status->partition_id);
|
|
471
|
+
set_uint32(env, object, "flags", status->flags);
|
|
472
|
+
set_boolean(env, object, "enabled", (status->flags & SFS_PARTITION_ENABLED) != 0u);
|
|
473
|
+
set_uint64(env, object, "quotaBytes", status->quota_bytes);
|
|
474
|
+
set_uint64(env, object, "allocatedBytes", status->allocated_bytes);
|
|
475
|
+
set_uint64(env, object, "segmentCount", status->segment_count);
|
|
476
|
+
set_uint64(env, object, "firstSegmentId", status->first_segment_id);
|
|
477
|
+
set_uint64(env, object, "activeSegmentId", status->active_segment_id);
|
|
478
|
+
set_uint64(env, object, "activeWriteOffset", status->active_write_offset);
|
|
479
|
+
set_uint64(env, object, "recordCount", status->record_count);
|
|
480
|
+
set_uint64(env, object, "payloadBytes", status->payload_bytes);
|
|
481
|
+
set_uint64(env, object, "firstSequence", status->first_sequence);
|
|
482
|
+
set_uint64(env, object, "lastSequence", status->last_sequence);
|
|
483
|
+
set_uint64(env, object, "evictedSegments", status->evicted_segments);
|
|
484
|
+
set_uint64(env, object, "evictedRecords", status->evicted_records);
|
|
485
|
+
set_uint64(env, object, "evictedPayloadBytes", status->evicted_payload_bytes);
|
|
486
|
+
return object;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
static napi_value binding_status(napi_env env, napi_callback_info info)
|
|
490
|
+
{
|
|
491
|
+
napi_value argv[1];
|
|
492
|
+
size_t argc = 1u;
|
|
493
|
+
node_sfs_handle_t *handle;
|
|
494
|
+
sfs_status_t status;
|
|
495
|
+
sfs_error_t error;
|
|
496
|
+
sfs_result_t result;
|
|
497
|
+
napi_value object;
|
|
498
|
+
napi_value partitions;
|
|
499
|
+
|
|
500
|
+
if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL) != napi_ok || argc != 1u) {
|
|
501
|
+
throw_napi(env, "status(handle) requires one argument");
|
|
502
|
+
return NULL;
|
|
503
|
+
}
|
|
504
|
+
handle = required_handle(env, argv[0]);
|
|
505
|
+
if (handle == NULL) return NULL;
|
|
506
|
+
memset(&status, 0, sizeof(status));
|
|
507
|
+
status.struct_size = sizeof(status);
|
|
508
|
+
result = sfs_status(handle->store, &status, &error);
|
|
509
|
+
if (result != SFS_OK) {
|
|
510
|
+
throw_sfs(env, result, &error);
|
|
511
|
+
return NULL;
|
|
512
|
+
}
|
|
513
|
+
(void)napi_create_object(env, &object);
|
|
514
|
+
set_uint32(env, object, "formatVersion", status.format_version);
|
|
515
|
+
set_uint32(env, object, "flags", status.flags);
|
|
516
|
+
set_boolean(env, object, "recoveredTail", (status.flags & SFS_STATUS_RECOVERED_TAIL) != 0u);
|
|
517
|
+
set_uint64(env, object, "segmentSize", status.segment_size);
|
|
518
|
+
set_uint64(env, object, "segmentCount", status.segment_count);
|
|
519
|
+
set_uint64(env, object, "recordCount", status.record_count);
|
|
520
|
+
set_uint64(env, object, "payloadBytes", status.payload_bytes);
|
|
521
|
+
set_uint64(env, object, "nextSequence", status.next_sequence);
|
|
522
|
+
set_uint32(env, object, "recoveryPartitionId", status.recovery_partition_id);
|
|
523
|
+
set_uint64(env, object, "recoverySegmentId", status.recovery_segment_id);
|
|
524
|
+
set_uint64(env, object, "recoveryOffset", status.recovery_offset);
|
|
525
|
+
set_uint64(env, object, "recoveryDiscardedBytes", status.recovery_discarded_bytes);
|
|
526
|
+
(void)napi_create_array_with_length(env, SFS_MAX_PARTITIONS, &partitions);
|
|
527
|
+
for (uint32_t index = 0u; index < SFS_MAX_PARTITIONS; index += 1u) {
|
|
528
|
+
(void)napi_set_element(env, partitions, index, partition_status_value(env, &status.partitions[index]));
|
|
529
|
+
}
|
|
530
|
+
set_named(env, object, "partitions", partitions);
|
|
531
|
+
return object;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static napi_value binding_flush(napi_env env, napi_callback_info info)
|
|
535
|
+
{
|
|
536
|
+
napi_value argv[1];
|
|
537
|
+
size_t argc = 1u;
|
|
538
|
+
node_sfs_handle_t *handle;
|
|
539
|
+
sfs_error_t error;
|
|
540
|
+
sfs_result_t result;
|
|
541
|
+
if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL) != napi_ok || argc != 1u) {
|
|
542
|
+
throw_napi(env, "flush(handle) requires one argument");
|
|
543
|
+
return NULL;
|
|
544
|
+
}
|
|
545
|
+
handle = required_handle(env, argv[0]);
|
|
546
|
+
if (handle == NULL) return NULL;
|
|
547
|
+
result = sfs_flush(handle->store, &error);
|
|
548
|
+
if (result != SFS_OK) {
|
|
549
|
+
throw_sfs(env, result, &error);
|
|
550
|
+
return NULL;
|
|
551
|
+
}
|
|
552
|
+
return js_undefined(env);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
static napi_value binding_close(napi_env env, napi_callback_info info)
|
|
556
|
+
{
|
|
557
|
+
napi_value argv[1];
|
|
558
|
+
size_t argc = 1u;
|
|
559
|
+
node_sfs_handle_t *handle = NULL;
|
|
560
|
+
sfs_error_t error;
|
|
561
|
+
sfs_result_t result;
|
|
562
|
+
if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL) != napi_ok || argc != 1u
|
|
563
|
+
|| napi_get_value_external(env, argv[0], (void **)&handle) != napi_ok || handle == NULL) {
|
|
564
|
+
throw_napi(env, "close(handle) requires a native handle");
|
|
565
|
+
return NULL;
|
|
566
|
+
}
|
|
567
|
+
if (handle->store == NULL) return js_undefined(env);
|
|
568
|
+
result = sfs_close(handle->store, &error);
|
|
569
|
+
if (result != SFS_OK) {
|
|
570
|
+
throw_sfs(env, result, &error);
|
|
571
|
+
return NULL;
|
|
572
|
+
}
|
|
573
|
+
handle->store = NULL;
|
|
574
|
+
return js_undefined(env);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
static napi_value initialize(napi_env env, napi_value exports)
|
|
578
|
+
{
|
|
579
|
+
napi_property_descriptor properties[] = {
|
|
580
|
+
{"open", NULL, binding_open, NULL, NULL, NULL, napi_default, NULL},
|
|
581
|
+
{"append", NULL, binding_append, NULL, NULL, NULL, napi_default, NULL},
|
|
582
|
+
{"scan", NULL, binding_scan, NULL, NULL, NULL, napi_default, NULL},
|
|
583
|
+
{"status", NULL, binding_status, NULL, NULL, NULL, napi_default, NULL},
|
|
584
|
+
{"flush", NULL, binding_flush, NULL, NULL, NULL, napi_default, NULL},
|
|
585
|
+
{"close", NULL, binding_close, NULL, NULL, NULL, napi_default, NULL},
|
|
586
|
+
};
|
|
587
|
+
if (napi_define_properties(env,
|
|
588
|
+
exports,
|
|
589
|
+
sizeof(properties) / sizeof(properties[0]),
|
|
590
|
+
properties) != napi_ok) {
|
|
591
|
+
throw_napi(env, "unable to initialize segmented fact store binding");
|
|
592
|
+
return NULL;
|
|
593
|
+
}
|
|
594
|
+
return exports;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
NAPI_MODULE(NODE_GYP_MODULE_NAME, initialize)
|