@nodegx/preview 0.2.5 → 0.2.6
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/dist/backend/cli.js +1225 -656
- package/dist/backend/vm/provision-app.sh +41 -0
- package/dist/browser/noodl-graph-target.js +95 -95
- package/dist/browser/noodl-preview-in-page.js +23 -20
- package/dist/external/deploy/noodl.deploy.js +1 -1
- package/dist/nodegx-deploy.cjs +1000 -581
- package/dist/nodegx-deploy.inputs.json +5 -0
- package/dist/noodl-preview.cjs +820 -531
- package/dist/noodl-preview.inputs.json +4 -0
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/noodl-preview.cjs
CHANGED
|
@@ -18277,6 +18277,27 @@ var init_run_on_value_change = __esm({
|
|
|
18277
18277
|
}
|
|
18278
18278
|
});
|
|
18279
18279
|
|
|
18280
|
+
// ../noodl-runtime/src/tracecause.ts
|
|
18281
|
+
function currentTraceCause(context) {
|
|
18282
|
+
const c = context;
|
|
18283
|
+
return c && c.traceEnabled ? c._currentCause || 0 : 0;
|
|
18284
|
+
}
|
|
18285
|
+
function withTraceCause(context, cause, fn) {
|
|
18286
|
+
const c = context;
|
|
18287
|
+
if (!cause || !c || !c.traceEnabled) return fn();
|
|
18288
|
+
const previous = c._currentCause;
|
|
18289
|
+
c._currentCause = cause;
|
|
18290
|
+
try {
|
|
18291
|
+
return fn();
|
|
18292
|
+
} finally {
|
|
18293
|
+
c._currentCause = previous;
|
|
18294
|
+
}
|
|
18295
|
+
}
|
|
18296
|
+
var init_tracecause = __esm({
|
|
18297
|
+
"../noodl-runtime/src/tracecause.ts"() {
|
|
18298
|
+
}
|
|
18299
|
+
});
|
|
18300
|
+
|
|
18280
18301
|
// ../noodl-runtime/src/outputproperty.ts
|
|
18281
18302
|
var require_outputproperty = __commonJS({
|
|
18282
18303
|
"../noodl-runtime/src/outputproperty.ts"(exports2, module2) {
|
|
@@ -18452,6 +18473,7 @@ var require_node2 = __commonJS({
|
|
|
18452
18473
|
init_diagnostics();
|
|
18453
18474
|
init_outcome();
|
|
18454
18475
|
init_run_on_value_change();
|
|
18476
|
+
init_tracecause();
|
|
18455
18477
|
var OutputProperty = require_outputproperty();
|
|
18456
18478
|
var NAN_INPUT_KEY = "node/nan-input/";
|
|
18457
18479
|
var SIGNAL_PULSE = Object.freeze({ __noodlSignalPulse: true });
|
|
@@ -18964,6 +18986,8 @@ var require_node2 = __commonJS({
|
|
|
18964
18986
|
});
|
|
18965
18987
|
Node17.prototype.beginOutcome = function(inputData) {
|
|
18966
18988
|
const token = { reported: void 0 };
|
|
18989
|
+
const cause = currentTraceCause(this.context);
|
|
18990
|
+
if (cause) token.cause = cause;
|
|
18967
18991
|
const scope = this.nodeScope;
|
|
18968
18992
|
const runContext = scope && scope.runContext;
|
|
18969
18993
|
if (runContext && runContext.beginStep) {
|
|
@@ -18999,6 +19023,10 @@ var require_node2 = __commonJS({
|
|
|
18999
19023
|
return;
|
|
19000
19024
|
}
|
|
19001
19025
|
token.reported = outcome;
|
|
19026
|
+
const traceContext = this.context;
|
|
19027
|
+
const tokenCause = token.cause;
|
|
19028
|
+
const causeBefore = traceContext ? traceContext._currentCause : 0;
|
|
19029
|
+
if (tokenCause && traceContext && traceContext.traceEnabled) traceContext._currentCause = tokenCause;
|
|
19002
19030
|
this._raisingForOutcome = true;
|
|
19003
19031
|
try {
|
|
19004
19032
|
if (outcome === "failure" && !(options && options.raise === false)) {
|
|
@@ -19028,6 +19056,7 @@ var require_node2 = __commonJS({
|
|
|
19028
19056
|
}
|
|
19029
19057
|
} finally {
|
|
19030
19058
|
this._raisingForOutcome = false;
|
|
19059
|
+
if (tokenCause && traceContext && traceContext.traceEnabled) traceContext._currentCause = causeBefore;
|
|
19031
19060
|
}
|
|
19032
19061
|
const step = token.step;
|
|
19033
19062
|
if (step !== void 0 && step !== null) {
|
|
@@ -19123,7 +19152,12 @@ var require_node2 = __commonJS({
|
|
|
19123
19152
|
this.flagDirty();
|
|
19124
19153
|
};
|
|
19125
19154
|
Node17.prototype.scheduleAfterInputsHaveUpdated = function(callback) {
|
|
19126
|
-
this.
|
|
19155
|
+
const cause = currentTraceCause(this.context);
|
|
19156
|
+
this._afterInputsHaveUpdatedCallbacks.push(
|
|
19157
|
+
cause ? function() {
|
|
19158
|
+
return withTraceCause(this.context, cause, () => callback.call(this));
|
|
19159
|
+
} : callback
|
|
19160
|
+
);
|
|
19127
19161
|
this.flagDirty();
|
|
19128
19162
|
};
|
|
19129
19163
|
Node17.prototype.setNodeModel = function(nodeModel) {
|
|
@@ -19226,6 +19260,60 @@ var require_node2 = __commonJS({
|
|
|
19226
19260
|
}
|
|
19227
19261
|
});
|
|
19228
19262
|
|
|
19263
|
+
// ../nodegx-project-contract/renamed-ports.ts
|
|
19264
|
+
function renamedOutput(typeName2, port) {
|
|
19265
|
+
const renames = own.call(RENAMED_OUTPUTS, typeName2) ? RENAMED_OUTPUTS[typeName2] : void 0;
|
|
19266
|
+
return renames && own.call(renames, port) ? renames[port] : void 0;
|
|
19267
|
+
}
|
|
19268
|
+
var RENAMED_OUTPUTS, own;
|
|
19269
|
+
var init_renamed_ports = __esm({
|
|
19270
|
+
"../nodegx-project-contract/renamed-ports.ts"() {
|
|
19271
|
+
"use strict";
|
|
19272
|
+
RENAMED_OUTPUTS = {
|
|
19273
|
+
AddDbModelRelation: { relationAdded: "done" },
|
|
19274
|
+
Boolean: { stored: "completed" },
|
|
19275
|
+
CloudFunction2: { success: "done" },
|
|
19276
|
+
CollectionClear: { modified: "done" },
|
|
19277
|
+
CollectionInsert: { modified: "done" },
|
|
19278
|
+
CollectionNew: { created: "done" },
|
|
19279
|
+
CollectionRemove: { modified: "done" },
|
|
19280
|
+
Color: { stored: "completed" },
|
|
19281
|
+
DeleteDbModelProperties: { deleted: "done" },
|
|
19282
|
+
"Event Sender": { sent: "done" },
|
|
19283
|
+
NavigationClosePopup: { success: "done" },
|
|
19284
|
+
NewDbModelProperties: { created: "done" },
|
|
19285
|
+
NewModel: { created: "done" },
|
|
19286
|
+
Number: { stored: "completed" },
|
|
19287
|
+
"Open File Picker": { success: "done", cancelled: "unchanged" },
|
|
19288
|
+
PageStackNavigate: { navigated: "done" },
|
|
19289
|
+
PageStackNavigateBack: { success: "done" },
|
|
19290
|
+
PageStackNavigateToPath: { success: "done" },
|
|
19291
|
+
RemoveDbModelRelation: { relationRemoved: "done" },
|
|
19292
|
+
RouterNavigate: { navigated: "done" },
|
|
19293
|
+
RunTasks: { success: "done" },
|
|
19294
|
+
SetDbModelProperties: { stored: "done" },
|
|
19295
|
+
SetModelProperties: { stored: "done" },
|
|
19296
|
+
"Sign File URL": { success: "done" },
|
|
19297
|
+
String: { stored: "completed" },
|
|
19298
|
+
"Unique Id": { generated: "done" },
|
|
19299
|
+
"Upload File": { success: "done" },
|
|
19300
|
+
"net.noodl.HTTP": { success: "done" },
|
|
19301
|
+
"net.noodl.SetComponentObjectProperties": { stored: "done" },
|
|
19302
|
+
"net.noodl.SetParentComponentObjectProperties": { stored: "done" },
|
|
19303
|
+
"net.noodl.externallink": { success: "done" },
|
|
19304
|
+
"net.noodl.user.LogIn": { success: "done" },
|
|
19305
|
+
"net.noodl.user.LogOut": { success: "done" },
|
|
19306
|
+
"net.noodl.user.RequestMagicLink": { success: "done" },
|
|
19307
|
+
"net.noodl.user.SetUserProperties": { success: "done" },
|
|
19308
|
+
"net.noodl.user.SignInWith": { success: "done" },
|
|
19309
|
+
"net.noodl.user.SignUp": { success: "done" },
|
|
19310
|
+
"noodl.cloud.response": { sent: "done" },
|
|
19311
|
+
"noodl.cloud.sendemail": { sent: "done", failed: "failure" }
|
|
19312
|
+
};
|
|
19313
|
+
own = Object.prototype.hasOwnProperty;
|
|
19314
|
+
}
|
|
19315
|
+
});
|
|
19316
|
+
|
|
19229
19317
|
// ../noodl-runtime/src/guid.ts
|
|
19230
19318
|
var require_guid = __commonJS({
|
|
19231
19319
|
"../noodl-runtime/src/guid.ts"(exports2, module2) {
|
|
@@ -19243,6 +19331,7 @@ var require_guid = __commonJS({
|
|
|
19243
19331
|
var require_nodescope = __commonJS({
|
|
19244
19332
|
"../noodl-runtime/src/nodescope.ts"(exports2, module2) {
|
|
19245
19333
|
"use strict";
|
|
19334
|
+
init_renamed_ports();
|
|
19246
19335
|
var guid4 = require_guid();
|
|
19247
19336
|
function hasNode(map2, id) {
|
|
19248
19337
|
return Object.prototype.hasOwnProperty.call(map2, id);
|
|
@@ -19275,11 +19364,15 @@ var require_nodescope = __commonJS({
|
|
|
19275
19364
|
var sourceNode = this.getNodeWithId(connectionData.sourceId), targetNode = this.getNodeWithId(connectionData.targetId);
|
|
19276
19365
|
targetNode.registerInputIfNeeded(connectionData.targetPort);
|
|
19277
19366
|
sourceNode.registerOutputIfNeeded(connectionData.sourcePort);
|
|
19278
|
-
targetNode.connectInput(connectionData.targetPort, sourceNode, connectionData.sourcePort);
|
|
19367
|
+
targetNode.connectInput(connectionData.targetPort, sourceNode, sourcePortOf(sourceNode, connectionData.sourcePort));
|
|
19279
19368
|
} catch (e) {
|
|
19280
19369
|
console.error(e.message);
|
|
19281
19370
|
}
|
|
19282
19371
|
};
|
|
19372
|
+
function sourcePortOf(sourceNode, port) {
|
|
19373
|
+
if (sourceNode.hasOutput(port)) return port;
|
|
19374
|
+
return renamedOutput(sourceNode.name, port) ?? port;
|
|
19375
|
+
}
|
|
19283
19376
|
NodeScope.prototype.setNodeParameters = function(node, nodeModel) {
|
|
19284
19377
|
const variant = this.context.variants.getVariant(nodeModel.type, nodeModel.variant);
|
|
19285
19378
|
if (variant) {
|
|
@@ -19287,10 +19380,10 @@ var require_nodescope = __commonJS({
|
|
|
19287
19380
|
} else {
|
|
19288
19381
|
const parameters = nodeModel.parameters;
|
|
19289
19382
|
var inputNames = Object.keys(parameters);
|
|
19290
|
-
const
|
|
19383
|
+
const RUN_ON_CHANGE_PREFIX4 = "runOnChange-";
|
|
19291
19384
|
const metadata = this.context.nodeRegister.hasNode(node.name) ? this.context.nodeRegister.getNodeMetadata(node.name) : void 0;
|
|
19292
19385
|
const priorityOf = function(name2) {
|
|
19293
|
-
if (name2.indexOf(
|
|
19386
|
+
if (name2.indexOf(RUN_ON_CHANGE_PREFIX4) === 0) return Number.MAX_SAFE_INTEGER;
|
|
19294
19387
|
const input2 = metadata ? metadata.inputs[name2] : void 0;
|
|
19295
19388
|
return input2 ? input2.inputPriority : 0;
|
|
19296
19389
|
};
|
|
@@ -19464,7 +19557,9 @@ var require_nodescope = __commonJS({
|
|
|
19464
19557
|
};
|
|
19465
19558
|
NodeScope.prototype.removeConnection = function(connectionModel) {
|
|
19466
19559
|
var targetNode = this.getNodeWithId(connectionModel.targetId);
|
|
19467
|
-
|
|
19560
|
+
const sourceNode = this.hasNodeWithId(connectionModel.sourceId) ? this.getNodeWithId(connectionModel.sourceId) : void 0;
|
|
19561
|
+
const sourcePort = sourceNode ? sourcePortOf(sourceNode, connectionModel.sourcePort) : connectionModel.sourcePort;
|
|
19562
|
+
targetNode.removeInputConnection(connectionModel.targetPort, connectionModel.sourceId, sourcePort);
|
|
19468
19563
|
};
|
|
19469
19564
|
NodeScope.prototype.setComponentModel = async function(componentModel) {
|
|
19470
19565
|
this.componentModel = componentModel;
|
|
@@ -27078,7 +27173,9 @@ var init_function_ports = __esm({
|
|
|
27078
27173
|
INPUT_PATTERNS = [/Inputs\.([A-Za-z0-9_]+)/g, /Inputs\s*\[\s*(?:'([^'\n]*)'|"([^"\n]*)")\s*\]/g];
|
|
27079
27174
|
SIGNAL_PATTERNS = [
|
|
27080
27175
|
/Outputs\.([A-Za-z0-9_]+)\s*\(\s*\)/g,
|
|
27081
|
-
/Outputs\s*\[\s*(?:'([^'\n]*)'|"([^"\n]*)")\s*\]\(\s*\)/g
|
|
27176
|
+
/Outputs\s*\[\s*(?:'([^'\n]*)'|"([^"\n]*)")\s*\]\(\s*\)/g,
|
|
27177
|
+
/Outputs\.([A-Za-z0-9_]+)\.send\s*\(\s*\)/g,
|
|
27178
|
+
/Outputs\s*\[\s*(?:'([^'\n]*)'|"([^"\n]*)")\s*\]\.send\s*\(\s*\)/g
|
|
27082
27179
|
];
|
|
27083
27180
|
OUTPUT_PATTERNS = [/Outputs\.([A-Za-z0-9_]+)/g, /Outputs\s*\[\s*"([^"]*)"\s*\]/g];
|
|
27084
27181
|
REGEX_AFTER = /* @__PURE__ */ new Set(["(", ",", "=", ":", "[", "!", "&", "|", "?", "{", "}", ";", "+", "-", "*", "%", "<", ">", "~", "^"]);
|
|
@@ -27095,6 +27192,7 @@ var require_simplejavascript = __commonJS({
|
|
|
27095
27192
|
init_functionDiagnostics();
|
|
27096
27193
|
init_scriptfiles();
|
|
27097
27194
|
init_function_ports();
|
|
27195
|
+
init_tracecause();
|
|
27098
27196
|
var Node17 = require_node2();
|
|
27099
27197
|
var JavascriptNodeParser4 = require_javascriptnodeparser();
|
|
27100
27198
|
var { logJavaScriptNodeError: logJavaScriptNodeError2, thrownMessage: thrownMessage3 } = (init_utils(), __toCommonJS(utils_exports));
|
|
@@ -27464,11 +27562,12 @@ var require_simplejavascript = __commonJS({
|
|
|
27464
27562
|
}
|
|
27465
27563
|
const inputs = this._internal.inputValues;
|
|
27466
27564
|
const outputs = this._internal.outputValuesProxy;
|
|
27565
|
+
const runCause = currentTraceCause(this.context);
|
|
27467
27566
|
placingSignalPorts(this).forEach((key) => {
|
|
27468
27567
|
const _sendSignal = () => {
|
|
27469
27568
|
this._internal.outputWrites.add(key.substring("out-".length));
|
|
27470
27569
|
publishHeldWrites(this);
|
|
27471
|
-
if (this.hasOutput(key)) this.sendSignalOnOutput(key);
|
|
27570
|
+
if (this.hasOutput(key)) withTraceCause(this.context, runCause, () => this.sendSignalOnOutput(key));
|
|
27472
27571
|
};
|
|
27473
27572
|
const signalValue = _sendSignal;
|
|
27474
27573
|
signalValue.send = _sendSignal;
|
|
@@ -27493,7 +27592,7 @@ var require_simplejavascript = __commonJS({
|
|
|
27493
27592
|
this._internal.lastError = "";
|
|
27494
27593
|
this.flagOutputDirty("error");
|
|
27495
27594
|
}
|
|
27496
|
-
this.sendSignalOnOutput("success");
|
|
27595
|
+
withTraceCause(this.context, runCause, () => this.sendSignalOnOutput("success"));
|
|
27497
27596
|
reportOutcomes(this, tokens, "done");
|
|
27498
27597
|
}
|
|
27499
27598
|
} catch (e) {
|
|
@@ -35613,6 +35712,466 @@ var init_TokenLifecycle = __esm({
|
|
|
35613
35712
|
}
|
|
35614
35713
|
});
|
|
35615
35714
|
|
|
35715
|
+
// ../noodl-runtime/src/api/backends/ParseAuthAdapter.ts
|
|
35716
|
+
function pageSays(response, phrase) {
|
|
35717
|
+
return typeof response === "string" && response.indexOf(phrase) !== -1;
|
|
35718
|
+
}
|
|
35719
|
+
function htmlPageError(error, invalidPhrase, invalidMessage, fallback) {
|
|
35720
|
+
if (typeof error !== "string" || error.indexOf("<") === -1) return error || fallback;
|
|
35721
|
+
return error.indexOf(invalidPhrase) !== -1 ? invalidMessage : fallback;
|
|
35722
|
+
}
|
|
35723
|
+
function sessionTokenOf(session) {
|
|
35724
|
+
return session ? session.sessionToken : void 0;
|
|
35725
|
+
}
|
|
35726
|
+
var guid, HANDOFF_PARAM, AUTH_ERROR_PARAM, SESSION_MOVED_MESSAGE, ParseAuthAdapter;
|
|
35727
|
+
var init_ParseAuthAdapter = __esm({
|
|
35728
|
+
"../noodl-runtime/src/api/backends/ParseAuthAdapter.ts"() {
|
|
35729
|
+
init_AuthEvents();
|
|
35730
|
+
init_SessionStore();
|
|
35731
|
+
init_TokenLifecycle();
|
|
35732
|
+
guid = require_guid();
|
|
35733
|
+
HANDOFF_PARAM = "nodegx_auth";
|
|
35734
|
+
AUTH_ERROR_PARAM = "nodegx_auth_error";
|
|
35735
|
+
SESSION_MOVED_MESSAGE = "Someone signed in or out while this was being checked, so its answer was not used. Check again.";
|
|
35736
|
+
ParseAuthAdapter = class extends AuthEvents {
|
|
35737
|
+
constructor(options) {
|
|
35738
|
+
super();
|
|
35739
|
+
/** BAK-004: the state of a sign-in returning from a provider or a magic link. */
|
|
35740
|
+
this.oauthReturn = { inProgress: false };
|
|
35741
|
+
/**
|
|
35742
|
+
* One store and one controller per backend, keyed by application id.
|
|
35743
|
+
*
|
|
35744
|
+
* Per handle rather than per adapter because the contract's whole point is
|
|
35745
|
+
* that a project may have more than one backend, and two backends have two
|
|
35746
|
+
* sessions — the phase decided explicitly that they are never shared.
|
|
35747
|
+
*/
|
|
35748
|
+
this.stores = /* @__PURE__ */ new Map();
|
|
35749
|
+
this.controllers = /* @__PURE__ */ new Map();
|
|
35750
|
+
this.serializeObject = options.serializeObject;
|
|
35751
|
+
this.createStore = options.createStore || parseSessionStore;
|
|
35752
|
+
this.lifecycle = options.lifecycle || { kind: "eternal" };
|
|
35753
|
+
}
|
|
35754
|
+
// ── Session storage ──────────────────────────────────────────────────────
|
|
35755
|
+
sessionStore(handle) {
|
|
35756
|
+
const appId = handle.publicToken;
|
|
35757
|
+
const cacheKey = String(appId);
|
|
35758
|
+
let store = this.stores.get(cacheKey);
|
|
35759
|
+
if (store === void 0) {
|
|
35760
|
+
store = this.createStore(appId);
|
|
35761
|
+
this.stores.set(cacheKey, store);
|
|
35762
|
+
}
|
|
35763
|
+
return store;
|
|
35764
|
+
}
|
|
35765
|
+
/**
|
|
35766
|
+
* The lifecycle controller for this backend.
|
|
35767
|
+
*
|
|
35768
|
+
* On Parse this is an `eternal` controller: it arms no timer, subscribes to no
|
|
35769
|
+
* storage events, and its gate is a synchronous pass-through. It is on the
|
|
35770
|
+
* request path anyway, so that BCN-004 adds a `performRefresh` rather than a
|
|
35771
|
+
* call site.
|
|
35772
|
+
*/
|
|
35773
|
+
lifecycleController(handle) {
|
|
35774
|
+
const cacheKey = String(handle.publicToken);
|
|
35775
|
+
let controller = this.controllers.get(cacheKey);
|
|
35776
|
+
if (controller === void 0) {
|
|
35777
|
+
controller = new TokenLifecycleController({
|
|
35778
|
+
lifecycle: this.lifecycle,
|
|
35779
|
+
store: this.sessionStore(handle),
|
|
35780
|
+
onSessionLost: (reason) => {
|
|
35781
|
+
this.emitAuthEvent("sessionChanged", void 0);
|
|
35782
|
+
this.emitAuthEvent("sessionLost", reason);
|
|
35783
|
+
},
|
|
35784
|
+
onSessionClearedElsewhere: () => {
|
|
35785
|
+
this.emitAuthEvent("sessionChanged", void 0);
|
|
35786
|
+
this.emitAuthEvent("loggedOut");
|
|
35787
|
+
}
|
|
35788
|
+
});
|
|
35789
|
+
controller.start();
|
|
35790
|
+
this.controllers.set(cacheKey, controller);
|
|
35791
|
+
}
|
|
35792
|
+
return controller;
|
|
35793
|
+
}
|
|
35794
|
+
/** The stored session, or `undefined`. Not a contract method. */
|
|
35795
|
+
getCurrentUser(handle) {
|
|
35796
|
+
return this.sessionStore(handle).read();
|
|
35797
|
+
}
|
|
35798
|
+
setSession(handle, session) {
|
|
35799
|
+
this.sessionStore(handle).write(session);
|
|
35800
|
+
this.lifecycleController(handle).sessionChanged();
|
|
35801
|
+
this.emitAuthEvent("sessionChanged", session);
|
|
35802
|
+
}
|
|
35803
|
+
clearSession(handle) {
|
|
35804
|
+
this.sessionStore(handle).clear();
|
|
35805
|
+
this.lifecycleController(handle).sessionChanged();
|
|
35806
|
+
this.emitAuthEvent("sessionChanged", void 0);
|
|
35807
|
+
}
|
|
35808
|
+
// ── The wire ─────────────────────────────────────────────────────────────
|
|
35809
|
+
/**
|
|
35810
|
+
* The Parse auth seam. Moved from `userservice.ts:198` with one substitution:
|
|
35811
|
+
* `this.endpoint`/`this.appId` became `handle.url`/`handle.publicToken`.
|
|
35812
|
+
*
|
|
35813
|
+
* It is deliberately *not* `ParseWireAdapter._makeRequest`. The two differ in
|
|
35814
|
+
* three ways that all matter: this one sends `X-Parse-Installation-Id`, never
|
|
35815
|
+
* sends a master key, and hands its error callback Parse's `code` (the `209`
|
|
35816
|
+
* the session check turns on). Merging them would be a rewrite in a task
|
|
35817
|
+
* whose value is that nothing was rewritten.
|
|
35818
|
+
*/
|
|
35819
|
+
_makeRequest(handle, path8, options) {
|
|
35820
|
+
if (!handle.url) {
|
|
35821
|
+
if (options.error) {
|
|
35822
|
+
options.error({ error: "No active cloud service", status: 0 });
|
|
35823
|
+
}
|
|
35824
|
+
return;
|
|
35825
|
+
}
|
|
35826
|
+
const store = this.sessionStore(handle);
|
|
35827
|
+
this.lifecycleController(handle).withSession((session) => {
|
|
35828
|
+
const xhr = new XMLHttpRequest();
|
|
35829
|
+
xhr.onreadystatechange = function() {
|
|
35830
|
+
if (xhr.readyState === 4) {
|
|
35831
|
+
let json;
|
|
35832
|
+
try {
|
|
35833
|
+
json = JSON.parse(xhr.response);
|
|
35834
|
+
} catch (e) {
|
|
35835
|
+
}
|
|
35836
|
+
if (xhr.status === 200 || xhr.status === 201) {
|
|
35837
|
+
options.success(json || xhr.response);
|
|
35838
|
+
} else options.error(json || { error: xhr.responseText, status: xhr.status });
|
|
35839
|
+
}
|
|
35840
|
+
};
|
|
35841
|
+
xhr.open(options.method || "GET", handle.url + path8, true);
|
|
35842
|
+
xhr.setRequestHeader("X-Parse-Application-Id", handle.publicToken);
|
|
35843
|
+
const iidKey = parseInstallationIdKey(handle.publicToken);
|
|
35844
|
+
let _iid = store.readKey(iidKey);
|
|
35845
|
+
if (_iid === void 0) {
|
|
35846
|
+
_iid = guid();
|
|
35847
|
+
store.writeKey(iidKey, _iid);
|
|
35848
|
+
}
|
|
35849
|
+
xhr.setRequestHeader("X-Parse-Installation-Id", _iid);
|
|
35850
|
+
if (options.sessionToken) xhr.setRequestHeader("X-Parse-Session-Token", options.sessionToken);
|
|
35851
|
+
else if (session !== void 0) {
|
|
35852
|
+
xhr.setRequestHeader("X-Parse-Session-Token", session.sessionToken);
|
|
35853
|
+
}
|
|
35854
|
+
xhr.setRequestHeader("Content-Type", "application/json");
|
|
35855
|
+
xhr.send(JSON.stringify(options.content));
|
|
35856
|
+
});
|
|
35857
|
+
}
|
|
35858
|
+
// ── The ten ──────────────────────────────────────────────────────────────
|
|
35859
|
+
logIn(handle, options) {
|
|
35860
|
+
this._makeRequest(handle, "/login", {
|
|
35861
|
+
method: "POST",
|
|
35862
|
+
content: {
|
|
35863
|
+
username: options.username,
|
|
35864
|
+
password: options.password,
|
|
35865
|
+
_method: "GET"
|
|
35866
|
+
},
|
|
35867
|
+
success: (response) => {
|
|
35868
|
+
this.setSession(handle, response);
|
|
35869
|
+
options.success(response);
|
|
35870
|
+
this.emitAuthEvent("loggedIn", response);
|
|
35871
|
+
},
|
|
35872
|
+
error: (e) => {
|
|
35873
|
+
options.error(e.error);
|
|
35874
|
+
}
|
|
35875
|
+
});
|
|
35876
|
+
}
|
|
35877
|
+
logOut(handle, options) {
|
|
35878
|
+
this._makeRequest(handle, "/logout", {
|
|
35879
|
+
method: "POST",
|
|
35880
|
+
content: {},
|
|
35881
|
+
success: () => {
|
|
35882
|
+
this.clearSession(handle);
|
|
35883
|
+
options.success();
|
|
35884
|
+
this.emitAuthEvent("loggedOut");
|
|
35885
|
+
},
|
|
35886
|
+
error: (e) => {
|
|
35887
|
+
options.error(e.error);
|
|
35888
|
+
}
|
|
35889
|
+
});
|
|
35890
|
+
}
|
|
35891
|
+
signUp(handle, options) {
|
|
35892
|
+
const additionalUserProps = options.properties ? this.serializeObject({ ...options.properties }, "_User") : {};
|
|
35893
|
+
this._makeRequest(handle, "/users", {
|
|
35894
|
+
method: "POST",
|
|
35895
|
+
content: Object.assign({}, additionalUserProps, {
|
|
35896
|
+
username: options.username,
|
|
35897
|
+
password: options.password,
|
|
35898
|
+
email: options.email
|
|
35899
|
+
}),
|
|
35900
|
+
success: (response) => {
|
|
35901
|
+
const identity2 = { username: options.username };
|
|
35902
|
+
if (options.email !== void 0) identity2.email = options.email;
|
|
35903
|
+
const _cu = Object.assign(response, identity2, options.properties);
|
|
35904
|
+
if (_cu.emailVerified === void 0) _cu.emailVerified = false;
|
|
35905
|
+
this.setSession(handle, _cu);
|
|
35906
|
+
options.success(response);
|
|
35907
|
+
this.emitAuthEvent("loggedIn", _cu);
|
|
35908
|
+
},
|
|
35909
|
+
error: (e) => {
|
|
35910
|
+
options.error(e.error);
|
|
35911
|
+
}
|
|
35912
|
+
});
|
|
35913
|
+
}
|
|
35914
|
+
fetchCurrentUser(handle, options) {
|
|
35915
|
+
const asked = sessionTokenOf(this.getCurrentUser(handle));
|
|
35916
|
+
this._makeRequest(handle, "/users/me", {
|
|
35917
|
+
method: "GET",
|
|
35918
|
+
sessionToken: options.sessionToken,
|
|
35919
|
+
success: (response) => {
|
|
35920
|
+
if (sessionTokenOf(this.getCurrentUser(handle)) !== asked) {
|
|
35921
|
+
options.error(SESSION_MOVED_MESSAGE);
|
|
35922
|
+
return;
|
|
35923
|
+
}
|
|
35924
|
+
this.setSession(handle, response);
|
|
35925
|
+
this.emitAuthEvent("sessionGained", response);
|
|
35926
|
+
options.success(response);
|
|
35927
|
+
},
|
|
35928
|
+
error: (e) => {
|
|
35929
|
+
if (sessionTokenOf(this.getCurrentUser(handle)) !== asked) {
|
|
35930
|
+
options.error(SESSION_MOVED_MESSAGE);
|
|
35931
|
+
return;
|
|
35932
|
+
}
|
|
35933
|
+
if (e.code === 209) {
|
|
35934
|
+
this.sessionStore(handle).clear();
|
|
35935
|
+
this.emitAuthEvent("sessionLost");
|
|
35936
|
+
}
|
|
35937
|
+
options.error(e.error);
|
|
35938
|
+
}
|
|
35939
|
+
});
|
|
35940
|
+
}
|
|
35941
|
+
verifyEmail(handle, options) {
|
|
35942
|
+
this._makeRequest(
|
|
35943
|
+
handle,
|
|
35944
|
+
"/apps/" + handle.publicToken + "/verify_email?username=" + options.username + "&token=" + options.token,
|
|
35945
|
+
{
|
|
35946
|
+
method: "GET",
|
|
35947
|
+
// This endpoint answers with an HTML page rather than JSON, so the outcome has to be
|
|
35948
|
+
// read out of the page's text.
|
|
35949
|
+
success: (response) => {
|
|
35950
|
+
if (pageSays(response, "Successfully verified your email")) {
|
|
35951
|
+
options.success();
|
|
35952
|
+
} else if (pageSays(response, "Invalid Verification Link")) {
|
|
35953
|
+
options.error("Invalid verification token");
|
|
35954
|
+
} else {
|
|
35955
|
+
options.error("Failed to verify email");
|
|
35956
|
+
}
|
|
35957
|
+
},
|
|
35958
|
+
error: (e) => {
|
|
35959
|
+
options.error(htmlPageError(e.error, "Invalid Verification Link", "Invalid verification token", "Failed to verify email"));
|
|
35960
|
+
}
|
|
35961
|
+
}
|
|
35962
|
+
);
|
|
35963
|
+
}
|
|
35964
|
+
sendEmailVerification(handle, options) {
|
|
35965
|
+
this._makeRequest(handle, "/verificationEmailRequest", {
|
|
35966
|
+
method: "POST",
|
|
35967
|
+
content: { email: options.email },
|
|
35968
|
+
success: () => {
|
|
35969
|
+
options.success();
|
|
35970
|
+
},
|
|
35971
|
+
error: (e) => {
|
|
35972
|
+
options.error(e.error);
|
|
35973
|
+
}
|
|
35974
|
+
});
|
|
35975
|
+
}
|
|
35976
|
+
resetPassword(handle, options) {
|
|
35977
|
+
this._makeRequest(handle, "/apps/" + handle.publicToken + "/request_password_reset", {
|
|
35978
|
+
method: "POST",
|
|
35979
|
+
content: {
|
|
35980
|
+
username: options.username,
|
|
35981
|
+
token: options.token,
|
|
35982
|
+
new_password: options.newPassword
|
|
35983
|
+
},
|
|
35984
|
+
success: (response) => {
|
|
35985
|
+
if (pageSays(response, "Password successfully reset") || pageSays(response, "Successfully updated your password")) {
|
|
35986
|
+
options.success();
|
|
35987
|
+
} else if (pageSays(response, "Invalid Link")) {
|
|
35988
|
+
options.error("Invalid or expired reset link");
|
|
35989
|
+
} else {
|
|
35990
|
+
options.error("Failed to reset password");
|
|
35991
|
+
}
|
|
35992
|
+
},
|
|
35993
|
+
error: (e) => {
|
|
35994
|
+
options.error(htmlPageError(e.error, "Invalid Link", "Invalid or expired reset link", "Failed to reset password"));
|
|
35995
|
+
}
|
|
35996
|
+
});
|
|
35997
|
+
}
|
|
35998
|
+
requestPasswordReset(handle, options) {
|
|
35999
|
+
this._makeRequest(handle, "/requestPasswordReset", {
|
|
36000
|
+
method: "POST",
|
|
36001
|
+
content: { email: options.email },
|
|
36002
|
+
success: () => {
|
|
36003
|
+
options.success();
|
|
36004
|
+
},
|
|
36005
|
+
error: (e) => {
|
|
36006
|
+
options.error(e.error);
|
|
36007
|
+
}
|
|
36008
|
+
});
|
|
36009
|
+
}
|
|
36010
|
+
/**
|
|
36011
|
+
* Send the browser to a provider. This NAVIGATES AWAY: nothing after it runs,
|
|
36012
|
+
* and the result arrives on a later page load through {@link consumeAuthReturn}.
|
|
36013
|
+
*
|
|
36014
|
+
* `redirect` defaults to the current page (minus any leftover sign-in
|
|
36015
|
+
* parameters), so the user comes back where they were. The backend refuses
|
|
36016
|
+
* any target that is neither same-origin nor on its `redirectAllowList` — if
|
|
36017
|
+
* sign-in dead-ends with "origin not allowed", that list is the fix.
|
|
36018
|
+
*/
|
|
36019
|
+
signInWithProvider(handle, options) {
|
|
36020
|
+
if (!handle.url) {
|
|
36021
|
+
if (options.error) options.error("No active cloud service");
|
|
36022
|
+
return;
|
|
36023
|
+
}
|
|
36024
|
+
if (!options.provider) {
|
|
36025
|
+
if (options.error) options.error("Sign In With: no provider was set.");
|
|
36026
|
+
return;
|
|
36027
|
+
}
|
|
36028
|
+
const redirect = options.redirect || this._currentUrlWithoutAuthParams();
|
|
36029
|
+
const url = `${handle.url}/oauth/${encodeURIComponent(options.provider)}/start?redirect=${encodeURIComponent(redirect)}`;
|
|
36030
|
+
window.location.href = url;
|
|
36031
|
+
}
|
|
36032
|
+
/**
|
|
36033
|
+
* Ask the backend to email a one-click sign-in link.
|
|
36034
|
+
*
|
|
36035
|
+
* Succeeds identically for a known and an unknown address — the endpoint is
|
|
36036
|
+
* anonymous and anti-enumerating by design, so "success" here means "the
|
|
36037
|
+
* request was accepted", never "an account exists". The node's help text says
|
|
36038
|
+
* so, because a UI that claims "check your inbox" only for real accounts
|
|
36039
|
+
* re-creates the oracle the endpoint removed.
|
|
36040
|
+
*/
|
|
36041
|
+
requestMagicLink(handle, options) {
|
|
36042
|
+
this._makeRequest(handle, "/auth/magic-link", {
|
|
36043
|
+
method: "POST",
|
|
36044
|
+
content: { email: options.email, redirect: options.redirect || this._currentUrlWithoutAuthParams() },
|
|
36045
|
+
success: () => options.success(),
|
|
36046
|
+
error: (e) => options.error(e.error)
|
|
36047
|
+
});
|
|
36048
|
+
}
|
|
36049
|
+
// ── Not contract, and deliberately so ────────────────────────────────────
|
|
36050
|
+
/**
|
|
36051
|
+
* Write user-profile fields onto the signed-in user.
|
|
36052
|
+
*
|
|
36053
|
+
* Not one of the ten. It is the `Set User Properties` node's whole
|
|
36054
|
+
* implementation, and BCN-006's Desired State §3 makes it schema-driven across
|
|
36055
|
+
* five backends — which is step 6, not this pass. It moves with the wire
|
|
36056
|
+
* because leaving it behind would have left a second `_makeRequest` in
|
|
36057
|
+
* `userservice.ts`, and the entire claim of this move is that there is one.
|
|
36058
|
+
*/
|
|
36059
|
+
setUserProperties(handle, options) {
|
|
36060
|
+
const _cu = this.getCurrentUser(handle);
|
|
36061
|
+
if (_cu === void 0) {
|
|
36062
|
+
options.error("Nobody is signed in.");
|
|
36063
|
+
return;
|
|
36064
|
+
}
|
|
36065
|
+
{
|
|
36066
|
+
const propsToSave = this.serializeObject({ ...options.properties }, "_User");
|
|
36067
|
+
const _content = Object.assign(
|
|
36068
|
+
{},
|
|
36069
|
+
{ email: options.email, username: options.username },
|
|
36070
|
+
propsToSave
|
|
36071
|
+
);
|
|
36072
|
+
delete _content.emailVerified;
|
|
36073
|
+
delete _content.createdAt;
|
|
36074
|
+
delete _content.updatedAt;
|
|
36075
|
+
this._makeRequest(handle, "/users/" + _cu.objectId, {
|
|
36076
|
+
method: "PUT",
|
|
36077
|
+
content: _content,
|
|
36078
|
+
success: (response) => {
|
|
36079
|
+
Object.assign(_cu, _content);
|
|
36080
|
+
this.setSession(handle, _cu);
|
|
36081
|
+
options.success(response);
|
|
36082
|
+
},
|
|
36083
|
+
error: (e) => {
|
|
36084
|
+
options.error(e.error);
|
|
36085
|
+
}
|
|
36086
|
+
});
|
|
36087
|
+
}
|
|
36088
|
+
}
|
|
36089
|
+
/** The sign-in methods this backend offers — for rendering a set of buttons. */
|
|
36090
|
+
listAuthProviders(handle, options) {
|
|
36091
|
+
this._makeRequest(handle, "/auth/providers", {
|
|
36092
|
+
method: "GET",
|
|
36093
|
+
success: (response) => options.success(response),
|
|
36094
|
+
error: (e) => options.error(e.error)
|
|
36095
|
+
});
|
|
36096
|
+
}
|
|
36097
|
+
// ── BAK-004 — the provider return leg ────────────────────────────────────
|
|
36098
|
+
/**
|
|
36099
|
+
* Look for a sign-in result in the current URL and act on it.
|
|
36100
|
+
*
|
|
36101
|
+
* Returns true when this page load IS a sign-in return, so the caller can skip
|
|
36102
|
+
* its ordinary stale-session validation.
|
|
36103
|
+
*
|
|
36104
|
+
* **Per backend, not contract.** BCN-006 step 5 is four different redirect
|
|
36105
|
+
* shapes — Parse `authData`, Directus SSO, Supabase, PocketBase
|
|
36106
|
+
* `auth-with-oauth2` — and this is the first of the four. What they have in
|
|
36107
|
+
* common is only the *outcome*: a session, established. That is where the
|
|
36108
|
+
* contract's surface is, and it is `signInWithProvider` plus a `loggedIn`.
|
|
36109
|
+
*/
|
|
36110
|
+
consumeAuthReturn(handle) {
|
|
36111
|
+
if (typeof window === "undefined" || !window.location) return false;
|
|
36112
|
+
let params;
|
|
36113
|
+
try {
|
|
36114
|
+
params = new URLSearchParams(window.location.search);
|
|
36115
|
+
} catch (e) {
|
|
36116
|
+
return false;
|
|
36117
|
+
}
|
|
36118
|
+
const code = params.get(HANDOFF_PARAM);
|
|
36119
|
+
const error = params.get(AUTH_ERROR_PARAM);
|
|
36120
|
+
if (!code && !error) return false;
|
|
36121
|
+
params.delete(HANDOFF_PARAM);
|
|
36122
|
+
params.delete(AUTH_ERROR_PARAM);
|
|
36123
|
+
this._stripAuthParamsFromUrl(params);
|
|
36124
|
+
if (error) {
|
|
36125
|
+
this.oauthReturn = { inProgress: false, succeeded: false, error };
|
|
36126
|
+
setTimeout(() => this.emitAuthEvent("oauthReturn", this.oauthReturn), 0);
|
|
36127
|
+
return true;
|
|
36128
|
+
}
|
|
36129
|
+
this.oauthReturn = { inProgress: true };
|
|
36130
|
+
this._makeRequest(handle, "/oauth/exchange", {
|
|
36131
|
+
method: "POST",
|
|
36132
|
+
content: { code },
|
|
36133
|
+
success: (response) => {
|
|
36134
|
+
this.setSession(handle, response);
|
|
36135
|
+
this.oauthReturn = {
|
|
36136
|
+
inProgress: false,
|
|
36137
|
+
succeeded: true,
|
|
36138
|
+
outcome: response.authOutcome,
|
|
36139
|
+
notice: response.authNotice || void 0
|
|
36140
|
+
};
|
|
36141
|
+
this.emitAuthEvent("oauthReturn", this.oauthReturn);
|
|
36142
|
+
this.emitAuthEvent("loggedIn", response);
|
|
36143
|
+
},
|
|
36144
|
+
error: (e) => {
|
|
36145
|
+
this.oauthReturn = {
|
|
36146
|
+
inProgress: false,
|
|
36147
|
+
succeeded: false,
|
|
36148
|
+
error: e && e.error || "Sign-in could not be completed."
|
|
36149
|
+
};
|
|
36150
|
+
this.emitAuthEvent("oauthReturn", this.oauthReturn);
|
|
36151
|
+
}
|
|
36152
|
+
});
|
|
36153
|
+
return true;
|
|
36154
|
+
}
|
|
36155
|
+
/** Rewrite the address bar without the sign-in parameters, keeping everything else. */
|
|
36156
|
+
_stripAuthParamsFromUrl(remaining) {
|
|
36157
|
+
if (!window.history || typeof window.history.replaceState !== "function") return;
|
|
36158
|
+
const query = remaining.toString();
|
|
36159
|
+
const cleaned = window.location.pathname + (query ? `?${query}` : "") + window.location.hash;
|
|
36160
|
+
try {
|
|
36161
|
+
window.history.replaceState(window.history.state, "", cleaned);
|
|
36162
|
+
} catch (e) {
|
|
36163
|
+
}
|
|
36164
|
+
}
|
|
36165
|
+
_currentUrlWithoutAuthParams() {
|
|
36166
|
+
const url = new URL(window.location.href);
|
|
36167
|
+
url.searchParams.delete(HANDOFF_PARAM);
|
|
36168
|
+
url.searchParams.delete(AUTH_ERROR_PARAM);
|
|
36169
|
+
return url.toString();
|
|
36170
|
+
}
|
|
36171
|
+
};
|
|
36172
|
+
}
|
|
36173
|
+
});
|
|
36174
|
+
|
|
35616
36175
|
// ../noodl-runtime/src/api/backends/RestAuthAdapter.ts
|
|
35617
36176
|
function restAuthProfileFor(type) {
|
|
35618
36177
|
return PROFILES[type];
|
|
@@ -35704,6 +36263,7 @@ var init_RestAuthAdapter = __esm({
|
|
|
35704
36263
|
"../noodl-runtime/src/api/backends/RestAuthAdapter.ts"() {
|
|
35705
36264
|
init_src();
|
|
35706
36265
|
init_AuthEvents();
|
|
36266
|
+
init_ParseAuthAdapter();
|
|
35707
36267
|
init_SessionStore();
|
|
35708
36268
|
init_TokenLifecycle();
|
|
35709
36269
|
DEFAULT_POCKETBASE_USER_COLLECTION = "users";
|
|
@@ -36269,12 +36829,20 @@ var init_RestAuthAdapter = __esm({
|
|
|
36269
36829
|
{ method, path: this.path(profile, profile.me), token, body: method === "POST" ? {} : void 0 },
|
|
36270
36830
|
{
|
|
36271
36831
|
ok: (body) => {
|
|
36832
|
+
if (sessionTokenOf(this.getCurrentUser(handle)) !== sessionTokenOf(stored)) {
|
|
36833
|
+
options.error(SESSION_MOVED_MESSAGE);
|
|
36834
|
+
return;
|
|
36835
|
+
}
|
|
36272
36836
|
const session = this.readSession(profile, body, Object.assign({}, stored, { sessionToken: token })) ?? Object.assign({}, stored, this.readUser(profile, body), { sessionToken: token });
|
|
36273
36837
|
this.setSession(handle, session);
|
|
36274
36838
|
this.emitAuthEvent("sessionGained", session);
|
|
36275
36839
|
options.success(session);
|
|
36276
36840
|
},
|
|
36277
36841
|
fail: (error) => {
|
|
36842
|
+
if (sessionTokenOf(this.getCurrentUser(handle)) !== sessionTokenOf(stored)) {
|
|
36843
|
+
options.error(SESSION_MOVED_MESSAGE);
|
|
36844
|
+
return;
|
|
36845
|
+
}
|
|
36278
36846
|
if (error.status === 401 || error.status === 403) {
|
|
36279
36847
|
this.sessionStore(handle).clear();
|
|
36280
36848
|
this.emitAuthEvent("sessionLost", error.error);
|
|
@@ -38775,8 +39343,9 @@ function schemaFor(collectionName2) {
|
|
|
38775
39343
|
try {
|
|
38776
39344
|
collection = CloudStore._collections[collectionName2];
|
|
38777
39345
|
} catch (e) {
|
|
38778
|
-
|
|
39346
|
+
collection = void 0;
|
|
38779
39347
|
}
|
|
39348
|
+
if (!collection) collection = hostCollection(collectionName2);
|
|
38780
39349
|
if (!collection) return void 0;
|
|
38781
39350
|
if (collection.schema) return { collection: collectionName2, properties: collection.schema.properties };
|
|
38782
39351
|
if (Array.isArray(collection.columns)) {
|
|
@@ -38790,6 +39359,15 @@ function schemaFor(collectionName2) {
|
|
|
38790
39359
|
}
|
|
38791
39360
|
return void 0;
|
|
38792
39361
|
}
|
|
39362
|
+
function hostCollection(collectionName2) {
|
|
39363
|
+
if (typeof _noodl_cloud_runtime_version === "undefined" || typeof _noodl_cloudservices === "undefined") return void 0;
|
|
39364
|
+
if (!_noodl_cloudservices || typeof _noodl_cloudservices.collections !== "function") return void 0;
|
|
39365
|
+
try {
|
|
39366
|
+
return (_noodl_cloudservices.collections() || []).find((c) => c && c.name === collectionName2);
|
|
39367
|
+
} catch (e) {
|
|
39368
|
+
return void 0;
|
|
39369
|
+
}
|
|
39370
|
+
}
|
|
38793
39371
|
function backendType() {
|
|
38794
39372
|
try {
|
|
38795
39373
|
const handle = CloudStore.instance && CloudStore.instance._handle && CloudStore.instance._handle();
|
|
@@ -70138,7 +70716,7 @@ function syncDataAttributesOnElement(node) {
|
|
|
70138
70716
|
node._appliedDataAttributes = Object.keys(want);
|
|
70139
70717
|
}
|
|
70140
70718
|
function claimDataAttributeInputs(node) {
|
|
70141
|
-
const
|
|
70719
|
+
const own2 = node.registerInputIfNeeded;
|
|
70142
70720
|
node.registerInputIfNeeded = function(name2) {
|
|
70143
70721
|
if (!this.hasInput(name2) && DATA_ATTRIBUTE_NAME.test(name2)) {
|
|
70144
70722
|
this.registerInput(name2, {
|
|
@@ -70150,7 +70728,7 @@ function claimDataAttributeInputs(node) {
|
|
|
70150
70728
|
});
|
|
70151
70729
|
return;
|
|
70152
70730
|
}
|
|
70153
|
-
return
|
|
70731
|
+
return own2 ? own2.call(this, name2) : void 0;
|
|
70154
70732
|
};
|
|
70155
70733
|
}
|
|
70156
70734
|
function scrollNodeIntoView(node, align) {
|
|
@@ -71700,7 +72278,7 @@ var init_Checkbox2 = __esm({
|
|
|
71700
72278
|
});
|
|
71701
72279
|
|
|
71702
72280
|
// ../noodl-viewer-react/src/guid.ts
|
|
71703
|
-
function
|
|
72281
|
+
function guid2() {
|
|
71704
72282
|
function s4() {
|
|
71705
72283
|
return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
|
|
71706
72284
|
}
|
|
@@ -71709,7 +72287,7 @@ function guid() {
|
|
|
71709
72287
|
var guid_default;
|
|
71710
72288
|
var init_guid = __esm({
|
|
71711
72289
|
"../noodl-viewer-react/src/guid.ts"() {
|
|
71712
|
-
guid_default =
|
|
72290
|
+
guid_default = guid2;
|
|
71713
72291
|
}
|
|
71714
72292
|
});
|
|
71715
72293
|
|
|
@@ -71929,6 +72507,17 @@ var init_checkbox = __esm({
|
|
|
71929
72507
|
});
|
|
71930
72508
|
|
|
71931
72509
|
// ../noodl-viewer-react/src/components/controls/Select/Select.tsx
|
|
72510
|
+
function domValueOf(item) {
|
|
72511
|
+
if (item.Value === void 0 || item.Value === null || typeof item.Value === "boolean") {
|
|
72512
|
+
const label = item.Label;
|
|
72513
|
+
return (label === void 0 || label === null || typeof label === "boolean" ? "" : String(label)).replace(/[ \t\n\f\r]+/g, " ").trim();
|
|
72514
|
+
}
|
|
72515
|
+
return String(item.Value);
|
|
72516
|
+
}
|
|
72517
|
+
function offersValue(items, value2) {
|
|
72518
|
+
if (!items || typeof value2 !== "string") return false;
|
|
72519
|
+
return items.some((item) => item !== null && item !== void 0 && domValueOf(item) === value2);
|
|
72520
|
+
}
|
|
71932
72521
|
function Select(props) {
|
|
71933
72522
|
const [value2, setValue] = (0, import_react6.useState)(props.value);
|
|
71934
72523
|
(0, import_react6.useEffect)(() => {
|
|
@@ -71942,7 +72531,7 @@ function Select(props) {
|
|
|
71942
72531
|
style2 = Object.assign({}, props.textStyle, style2);
|
|
71943
72532
|
style2.color = props.noodlNode.context.styles.resolveColor(style2.color);
|
|
71944
72533
|
}
|
|
71945
|
-
const selectedIndex = !props.items || value2 === void 0 ? -1 : props.items.findIndex((i2) => i2
|
|
72534
|
+
const selectedIndex = !props.items || value2 === void 0 ? -1 : props.items.findIndex((i2) => i2 !== null && i2 !== void 0 && domValueOf(i2) === value2);
|
|
71946
72535
|
const { height, ...otherStyles } = style2;
|
|
71947
72536
|
function _renderIcon() {
|
|
71948
72537
|
if (props.iconSourceType === "image" && props.iconImageSource !== void 0)
|
|
@@ -72050,7 +72639,7 @@ function Select(props) {
|
|
|
72050
72639
|
{
|
|
72051
72640
|
...inputProps,
|
|
72052
72641
|
disabled: !props.enabled,
|
|
72053
|
-
value:
|
|
72642
|
+
value: offersValue(props.items, value2) ? value2 : "",
|
|
72054
72643
|
...utils_default.controlEvents(props),
|
|
72055
72644
|
onChange: (e) => {
|
|
72056
72645
|
setValue(e.target.value);
|
|
@@ -72223,12 +72812,14 @@ var init_options = __esm({
|
|
|
72223
72812
|
this.props.id = "input-" + guid_default();
|
|
72224
72813
|
this.props.items = DEFAULT_ITEMS.map((item) => ({ ...item }));
|
|
72225
72814
|
this.props.value = this._internal.value = DEFAULT_ITEMS[0].Value;
|
|
72815
|
+
this._internal.valueIsSeed = true;
|
|
72226
72816
|
this.props.valueWrites = 0;
|
|
72227
72817
|
this.props.valueChanged = (value2) => {
|
|
72228
72818
|
const changed = this._internal.value !== value2;
|
|
72229
72819
|
this.props.value = this._internal.value = value2;
|
|
72230
72820
|
this.props.valueWrites++;
|
|
72231
72821
|
if (changed) {
|
|
72822
|
+
this._internal.valueIsSeed = false;
|
|
72232
72823
|
this.flagOutputDirty("value");
|
|
72233
72824
|
this.sendSignalOnOutput("onChange");
|
|
72234
72825
|
}
|
|
@@ -72281,6 +72872,16 @@ var init_options = __esm({
|
|
|
72281
72872
|
if (newValue && typeof newValue.on === "function") newValue.on("change", this._itemsChanged);
|
|
72282
72873
|
}
|
|
72283
72874
|
this.props.items = optionItems(this._internal.items);
|
|
72875
|
+
if (this._internal.valueIsSeed) {
|
|
72876
|
+
const offered = this.props.items;
|
|
72877
|
+
const seed = this._internal.value;
|
|
72878
|
+
if (!Array.isArray(offered) || !offered.some((item) => item && item.Value === seed)) {
|
|
72879
|
+
this._internal.valueIsSeed = false;
|
|
72880
|
+
this.props.value = this._internal.value = "";
|
|
72881
|
+
this.props.valueWrites++;
|
|
72882
|
+
this.flagOutputDirty("value");
|
|
72883
|
+
}
|
|
72884
|
+
}
|
|
72284
72885
|
this.forceUpdate();
|
|
72285
72886
|
}
|
|
72286
72887
|
},
|
|
@@ -72299,6 +72900,7 @@ var init_options = __esm({
|
|
|
72299
72900
|
}
|
|
72300
72901
|
const changed = value2 !== this._internal.value;
|
|
72301
72902
|
this.props.value = this._internal.value = value2;
|
|
72903
|
+
this._internal.valueIsSeed = false;
|
|
72302
72904
|
this.props.valueWrites++;
|
|
72303
72905
|
if (changed) {
|
|
72304
72906
|
this.forceUpdate();
|
|
@@ -78605,11 +79207,11 @@ var init_foreach = __esm({
|
|
|
78605
79207
|
const internal2 = this._internal;
|
|
78606
79208
|
const children = internal2.target.getChildren();
|
|
78607
79209
|
let at = children.indexOf(this) + 1;
|
|
78608
|
-
let
|
|
79210
|
+
let own2 = 0;
|
|
78609
79211
|
for (let i2 = at; i2 < children.length; i2++) {
|
|
78610
79212
|
if (internal2.itemNodes.indexOf(children[i2]) === -1) continue;
|
|
78611
|
-
if (
|
|
78612
|
-
|
|
79213
|
+
if (own2 === listIndex) return i2;
|
|
79214
|
+
own2++;
|
|
78613
79215
|
at = i2 + 1;
|
|
78614
79216
|
}
|
|
78615
79217
|
return at;
|
|
@@ -90999,8 +91601,8 @@ var init_timer = __esm({
|
|
|
90999
91601
|
const a = this._internal._animation;
|
|
91000
91602
|
if (a._isRunning !== true || this._internal.paused) return;
|
|
91001
91603
|
const left = a.durationLeft();
|
|
91002
|
-
const
|
|
91003
|
-
this._internal.paused = { left: typeof left === "number" && left >= 0 ? left : a.duration, ...
|
|
91604
|
+
const own2 = this._internal.resumed || { duration: a.duration, delay: a.delay };
|
|
91605
|
+
this._internal.paused = { left: typeof left === "number" && left >= 0 ? left : a.duration, ...own2 };
|
|
91004
91606
|
a.stop();
|
|
91005
91607
|
},
|
|
91006
91608
|
_onPageShown: function() {
|
|
@@ -95191,6 +95793,7 @@ __export(cloudfunction2_exports, {
|
|
|
95191
95793
|
default: () => cloudfunction2_default
|
|
95192
95794
|
});
|
|
95193
95795
|
function _makeRequest(path8, options) {
|
|
95796
|
+
options = holdOptionsForWrite(options);
|
|
95194
95797
|
const xhr = new XMLHttpRequest();
|
|
95195
95798
|
xhr.onreadystatechange = function() {
|
|
95196
95799
|
if (xhr.readyState === 4) {
|
|
@@ -95235,6 +95838,7 @@ var init_cloudfunction2 = __esm({
|
|
|
95235
95838
|
"../noodl-viewer-react/src/nodes/std-library/data/cloudfunction2.ts"() {
|
|
95236
95839
|
import_runtime10 = __toESM(require_noodl_runtime());
|
|
95237
95840
|
init_SessionStore();
|
|
95841
|
+
init_pressguard();
|
|
95238
95842
|
init_outcome();
|
|
95239
95843
|
CALL_ERROR_CODE = "cloud-function/call-failed";
|
|
95240
95844
|
CloudFunctionNode = {
|
|
@@ -97873,453 +98477,6 @@ var init_router_navigate = __esm({
|
|
|
97873
98477
|
}
|
|
97874
98478
|
});
|
|
97875
98479
|
|
|
97876
|
-
// ../noodl-runtime/src/api/backends/ParseAuthAdapter.ts
|
|
97877
|
-
function pageSays(response, phrase) {
|
|
97878
|
-
return typeof response === "string" && response.indexOf(phrase) !== -1;
|
|
97879
|
-
}
|
|
97880
|
-
function htmlPageError(error, invalidPhrase, invalidMessage, fallback) {
|
|
97881
|
-
if (typeof error !== "string" || error.indexOf("<") === -1) return error || fallback;
|
|
97882
|
-
return error.indexOf(invalidPhrase) !== -1 ? invalidMessage : fallback;
|
|
97883
|
-
}
|
|
97884
|
-
var guid2, HANDOFF_PARAM, AUTH_ERROR_PARAM, ParseAuthAdapter;
|
|
97885
|
-
var init_ParseAuthAdapter = __esm({
|
|
97886
|
-
"../noodl-runtime/src/api/backends/ParseAuthAdapter.ts"() {
|
|
97887
|
-
init_AuthEvents();
|
|
97888
|
-
init_SessionStore();
|
|
97889
|
-
init_TokenLifecycle();
|
|
97890
|
-
guid2 = require_guid();
|
|
97891
|
-
HANDOFF_PARAM = "nodegx_auth";
|
|
97892
|
-
AUTH_ERROR_PARAM = "nodegx_auth_error";
|
|
97893
|
-
ParseAuthAdapter = class extends AuthEvents {
|
|
97894
|
-
constructor(options) {
|
|
97895
|
-
super();
|
|
97896
|
-
/** BAK-004: the state of a sign-in returning from a provider or a magic link. */
|
|
97897
|
-
this.oauthReturn = { inProgress: false };
|
|
97898
|
-
/**
|
|
97899
|
-
* One store and one controller per backend, keyed by application id.
|
|
97900
|
-
*
|
|
97901
|
-
* Per handle rather than per adapter because the contract's whole point is
|
|
97902
|
-
* that a project may have more than one backend, and two backends have two
|
|
97903
|
-
* sessions — the phase decided explicitly that they are never shared.
|
|
97904
|
-
*/
|
|
97905
|
-
this.stores = /* @__PURE__ */ new Map();
|
|
97906
|
-
this.controllers = /* @__PURE__ */ new Map();
|
|
97907
|
-
this.serializeObject = options.serializeObject;
|
|
97908
|
-
this.createStore = options.createStore || parseSessionStore;
|
|
97909
|
-
this.lifecycle = options.lifecycle || { kind: "eternal" };
|
|
97910
|
-
}
|
|
97911
|
-
// ── Session storage ──────────────────────────────────────────────────────
|
|
97912
|
-
sessionStore(handle) {
|
|
97913
|
-
const appId = handle.publicToken;
|
|
97914
|
-
const cacheKey = String(appId);
|
|
97915
|
-
let store = this.stores.get(cacheKey);
|
|
97916
|
-
if (store === void 0) {
|
|
97917
|
-
store = this.createStore(appId);
|
|
97918
|
-
this.stores.set(cacheKey, store);
|
|
97919
|
-
}
|
|
97920
|
-
return store;
|
|
97921
|
-
}
|
|
97922
|
-
/**
|
|
97923
|
-
* The lifecycle controller for this backend.
|
|
97924
|
-
*
|
|
97925
|
-
* On Parse this is an `eternal` controller: it arms no timer, subscribes to no
|
|
97926
|
-
* storage events, and its gate is a synchronous pass-through. It is on the
|
|
97927
|
-
* request path anyway, so that BCN-004 adds a `performRefresh` rather than a
|
|
97928
|
-
* call site.
|
|
97929
|
-
*/
|
|
97930
|
-
lifecycleController(handle) {
|
|
97931
|
-
const cacheKey = String(handle.publicToken);
|
|
97932
|
-
let controller = this.controllers.get(cacheKey);
|
|
97933
|
-
if (controller === void 0) {
|
|
97934
|
-
controller = new TokenLifecycleController({
|
|
97935
|
-
lifecycle: this.lifecycle,
|
|
97936
|
-
store: this.sessionStore(handle),
|
|
97937
|
-
onSessionLost: (reason) => {
|
|
97938
|
-
this.emitAuthEvent("sessionChanged", void 0);
|
|
97939
|
-
this.emitAuthEvent("sessionLost", reason);
|
|
97940
|
-
},
|
|
97941
|
-
onSessionClearedElsewhere: () => {
|
|
97942
|
-
this.emitAuthEvent("sessionChanged", void 0);
|
|
97943
|
-
this.emitAuthEvent("loggedOut");
|
|
97944
|
-
}
|
|
97945
|
-
});
|
|
97946
|
-
controller.start();
|
|
97947
|
-
this.controllers.set(cacheKey, controller);
|
|
97948
|
-
}
|
|
97949
|
-
return controller;
|
|
97950
|
-
}
|
|
97951
|
-
/** The stored session, or `undefined`. Not a contract method. */
|
|
97952
|
-
getCurrentUser(handle) {
|
|
97953
|
-
return this.sessionStore(handle).read();
|
|
97954
|
-
}
|
|
97955
|
-
setSession(handle, session) {
|
|
97956
|
-
this.sessionStore(handle).write(session);
|
|
97957
|
-
this.lifecycleController(handle).sessionChanged();
|
|
97958
|
-
this.emitAuthEvent("sessionChanged", session);
|
|
97959
|
-
}
|
|
97960
|
-
clearSession(handle) {
|
|
97961
|
-
this.sessionStore(handle).clear();
|
|
97962
|
-
this.lifecycleController(handle).sessionChanged();
|
|
97963
|
-
this.emitAuthEvent("sessionChanged", void 0);
|
|
97964
|
-
}
|
|
97965
|
-
// ── The wire ─────────────────────────────────────────────────────────────
|
|
97966
|
-
/**
|
|
97967
|
-
* The Parse auth seam. Moved from `userservice.ts:198` with one substitution:
|
|
97968
|
-
* `this.endpoint`/`this.appId` became `handle.url`/`handle.publicToken`.
|
|
97969
|
-
*
|
|
97970
|
-
* It is deliberately *not* `ParseWireAdapter._makeRequest`. The two differ in
|
|
97971
|
-
* three ways that all matter: this one sends `X-Parse-Installation-Id`, never
|
|
97972
|
-
* sends a master key, and hands its error callback Parse's `code` (the `209`
|
|
97973
|
-
* the session check turns on). Merging them would be a rewrite in a task
|
|
97974
|
-
* whose value is that nothing was rewritten.
|
|
97975
|
-
*/
|
|
97976
|
-
_makeRequest(handle, path8, options) {
|
|
97977
|
-
if (!handle.url) {
|
|
97978
|
-
if (options.error) {
|
|
97979
|
-
options.error({ error: "No active cloud service", status: 0 });
|
|
97980
|
-
}
|
|
97981
|
-
return;
|
|
97982
|
-
}
|
|
97983
|
-
const store = this.sessionStore(handle);
|
|
97984
|
-
this.lifecycleController(handle).withSession((session) => {
|
|
97985
|
-
const xhr = new XMLHttpRequest();
|
|
97986
|
-
xhr.onreadystatechange = function() {
|
|
97987
|
-
if (xhr.readyState === 4) {
|
|
97988
|
-
let json;
|
|
97989
|
-
try {
|
|
97990
|
-
json = JSON.parse(xhr.response);
|
|
97991
|
-
} catch (e) {
|
|
97992
|
-
}
|
|
97993
|
-
if (xhr.status === 200 || xhr.status === 201) {
|
|
97994
|
-
options.success(json || xhr.response);
|
|
97995
|
-
} else options.error(json || { error: xhr.responseText, status: xhr.status });
|
|
97996
|
-
}
|
|
97997
|
-
};
|
|
97998
|
-
xhr.open(options.method || "GET", handle.url + path8, true);
|
|
97999
|
-
xhr.setRequestHeader("X-Parse-Application-Id", handle.publicToken);
|
|
98000
|
-
const iidKey = parseInstallationIdKey(handle.publicToken);
|
|
98001
|
-
let _iid = store.readKey(iidKey);
|
|
98002
|
-
if (_iid === void 0) {
|
|
98003
|
-
_iid = guid2();
|
|
98004
|
-
store.writeKey(iidKey, _iid);
|
|
98005
|
-
}
|
|
98006
|
-
xhr.setRequestHeader("X-Parse-Installation-Id", _iid);
|
|
98007
|
-
if (options.sessionToken) xhr.setRequestHeader("X-Parse-Session-Token", options.sessionToken);
|
|
98008
|
-
else if (session !== void 0) {
|
|
98009
|
-
xhr.setRequestHeader("X-Parse-Session-Token", session.sessionToken);
|
|
98010
|
-
}
|
|
98011
|
-
xhr.setRequestHeader("Content-Type", "application/json");
|
|
98012
|
-
xhr.send(JSON.stringify(options.content));
|
|
98013
|
-
});
|
|
98014
|
-
}
|
|
98015
|
-
// ── The ten ──────────────────────────────────────────────────────────────
|
|
98016
|
-
logIn(handle, options) {
|
|
98017
|
-
this._makeRequest(handle, "/login", {
|
|
98018
|
-
method: "POST",
|
|
98019
|
-
content: {
|
|
98020
|
-
username: options.username,
|
|
98021
|
-
password: options.password,
|
|
98022
|
-
_method: "GET"
|
|
98023
|
-
},
|
|
98024
|
-
success: (response) => {
|
|
98025
|
-
this.setSession(handle, response);
|
|
98026
|
-
options.success(response);
|
|
98027
|
-
this.emitAuthEvent("loggedIn", response);
|
|
98028
|
-
},
|
|
98029
|
-
error: (e) => {
|
|
98030
|
-
options.error(e.error);
|
|
98031
|
-
}
|
|
98032
|
-
});
|
|
98033
|
-
}
|
|
98034
|
-
logOut(handle, options) {
|
|
98035
|
-
this._makeRequest(handle, "/logout", {
|
|
98036
|
-
method: "POST",
|
|
98037
|
-
content: {},
|
|
98038
|
-
success: () => {
|
|
98039
|
-
this.clearSession(handle);
|
|
98040
|
-
options.success();
|
|
98041
|
-
this.emitAuthEvent("loggedOut");
|
|
98042
|
-
},
|
|
98043
|
-
error: (e) => {
|
|
98044
|
-
options.error(e.error);
|
|
98045
|
-
}
|
|
98046
|
-
});
|
|
98047
|
-
}
|
|
98048
|
-
signUp(handle, options) {
|
|
98049
|
-
const additionalUserProps = options.properties ? this.serializeObject({ ...options.properties }, "_User") : {};
|
|
98050
|
-
this._makeRequest(handle, "/users", {
|
|
98051
|
-
method: "POST",
|
|
98052
|
-
content: Object.assign({}, additionalUserProps, {
|
|
98053
|
-
username: options.username,
|
|
98054
|
-
password: options.password,
|
|
98055
|
-
email: options.email
|
|
98056
|
-
}),
|
|
98057
|
-
success: (response) => {
|
|
98058
|
-
const identity2 = { username: options.username };
|
|
98059
|
-
if (options.email !== void 0) identity2.email = options.email;
|
|
98060
|
-
const _cu = Object.assign(response, identity2, options.properties);
|
|
98061
|
-
if (_cu.emailVerified === void 0) _cu.emailVerified = false;
|
|
98062
|
-
this.setSession(handle, _cu);
|
|
98063
|
-
options.success(response);
|
|
98064
|
-
this.emitAuthEvent("loggedIn", _cu);
|
|
98065
|
-
},
|
|
98066
|
-
error: (e) => {
|
|
98067
|
-
options.error(e.error);
|
|
98068
|
-
}
|
|
98069
|
-
});
|
|
98070
|
-
}
|
|
98071
|
-
fetchCurrentUser(handle, options) {
|
|
98072
|
-
this._makeRequest(handle, "/users/me", {
|
|
98073
|
-
method: "GET",
|
|
98074
|
-
sessionToken: options.sessionToken,
|
|
98075
|
-
success: (response) => {
|
|
98076
|
-
this.setSession(handle, response);
|
|
98077
|
-
this.emitAuthEvent("sessionGained", response);
|
|
98078
|
-
options.success(response);
|
|
98079
|
-
},
|
|
98080
|
-
error: (e) => {
|
|
98081
|
-
if (e.code === 209) {
|
|
98082
|
-
this.sessionStore(handle).clear();
|
|
98083
|
-
this.emitAuthEvent("sessionLost");
|
|
98084
|
-
}
|
|
98085
|
-
options.error(e.error);
|
|
98086
|
-
}
|
|
98087
|
-
});
|
|
98088
|
-
}
|
|
98089
|
-
verifyEmail(handle, options) {
|
|
98090
|
-
this._makeRequest(
|
|
98091
|
-
handle,
|
|
98092
|
-
"/apps/" + handle.publicToken + "/verify_email?username=" + options.username + "&token=" + options.token,
|
|
98093
|
-
{
|
|
98094
|
-
method: "GET",
|
|
98095
|
-
// This endpoint answers with an HTML page rather than JSON, so the outcome has to be
|
|
98096
|
-
// read out of the page's text.
|
|
98097
|
-
success: (response) => {
|
|
98098
|
-
if (pageSays(response, "Successfully verified your email")) {
|
|
98099
|
-
options.success();
|
|
98100
|
-
} else if (pageSays(response, "Invalid Verification Link")) {
|
|
98101
|
-
options.error("Invalid verification token");
|
|
98102
|
-
} else {
|
|
98103
|
-
options.error("Failed to verify email");
|
|
98104
|
-
}
|
|
98105
|
-
},
|
|
98106
|
-
error: (e) => {
|
|
98107
|
-
options.error(htmlPageError(e.error, "Invalid Verification Link", "Invalid verification token", "Failed to verify email"));
|
|
98108
|
-
}
|
|
98109
|
-
}
|
|
98110
|
-
);
|
|
98111
|
-
}
|
|
98112
|
-
sendEmailVerification(handle, options) {
|
|
98113
|
-
this._makeRequest(handle, "/verificationEmailRequest", {
|
|
98114
|
-
method: "POST",
|
|
98115
|
-
content: { email: options.email },
|
|
98116
|
-
success: () => {
|
|
98117
|
-
options.success();
|
|
98118
|
-
},
|
|
98119
|
-
error: (e) => {
|
|
98120
|
-
options.error(e.error);
|
|
98121
|
-
}
|
|
98122
|
-
});
|
|
98123
|
-
}
|
|
98124
|
-
resetPassword(handle, options) {
|
|
98125
|
-
this._makeRequest(handle, "/apps/" + handle.publicToken + "/request_password_reset", {
|
|
98126
|
-
method: "POST",
|
|
98127
|
-
content: {
|
|
98128
|
-
username: options.username,
|
|
98129
|
-
token: options.token,
|
|
98130
|
-
new_password: options.newPassword
|
|
98131
|
-
},
|
|
98132
|
-
success: (response) => {
|
|
98133
|
-
if (pageSays(response, "Password successfully reset") || pageSays(response, "Successfully updated your password")) {
|
|
98134
|
-
options.success();
|
|
98135
|
-
} else if (pageSays(response, "Invalid Link")) {
|
|
98136
|
-
options.error("Invalid or expired reset link");
|
|
98137
|
-
} else {
|
|
98138
|
-
options.error("Failed to reset password");
|
|
98139
|
-
}
|
|
98140
|
-
},
|
|
98141
|
-
error: (e) => {
|
|
98142
|
-
options.error(htmlPageError(e.error, "Invalid Link", "Invalid or expired reset link", "Failed to reset password"));
|
|
98143
|
-
}
|
|
98144
|
-
});
|
|
98145
|
-
}
|
|
98146
|
-
requestPasswordReset(handle, options) {
|
|
98147
|
-
this._makeRequest(handle, "/requestPasswordReset", {
|
|
98148
|
-
method: "POST",
|
|
98149
|
-
content: { email: options.email },
|
|
98150
|
-
success: () => {
|
|
98151
|
-
options.success();
|
|
98152
|
-
},
|
|
98153
|
-
error: (e) => {
|
|
98154
|
-
options.error(e.error);
|
|
98155
|
-
}
|
|
98156
|
-
});
|
|
98157
|
-
}
|
|
98158
|
-
/**
|
|
98159
|
-
* Send the browser to a provider. This NAVIGATES AWAY: nothing after it runs,
|
|
98160
|
-
* and the result arrives on a later page load through {@link consumeAuthReturn}.
|
|
98161
|
-
*
|
|
98162
|
-
* `redirect` defaults to the current page (minus any leftover sign-in
|
|
98163
|
-
* parameters), so the user comes back where they were. The backend refuses
|
|
98164
|
-
* any target that is neither same-origin nor on its `redirectAllowList` — if
|
|
98165
|
-
* sign-in dead-ends with "origin not allowed", that list is the fix.
|
|
98166
|
-
*/
|
|
98167
|
-
signInWithProvider(handle, options) {
|
|
98168
|
-
if (!handle.url) {
|
|
98169
|
-
if (options.error) options.error("No active cloud service");
|
|
98170
|
-
return;
|
|
98171
|
-
}
|
|
98172
|
-
if (!options.provider) {
|
|
98173
|
-
if (options.error) options.error("Sign In With: no provider was set.");
|
|
98174
|
-
return;
|
|
98175
|
-
}
|
|
98176
|
-
const redirect = options.redirect || this._currentUrlWithoutAuthParams();
|
|
98177
|
-
const url = `${handle.url}/oauth/${encodeURIComponent(options.provider)}/start?redirect=${encodeURIComponent(redirect)}`;
|
|
98178
|
-
window.location.href = url;
|
|
98179
|
-
}
|
|
98180
|
-
/**
|
|
98181
|
-
* Ask the backend to email a one-click sign-in link.
|
|
98182
|
-
*
|
|
98183
|
-
* Succeeds identically for a known and an unknown address — the endpoint is
|
|
98184
|
-
* anonymous and anti-enumerating by design, so "success" here means "the
|
|
98185
|
-
* request was accepted", never "an account exists". The node's help text says
|
|
98186
|
-
* so, because a UI that claims "check your inbox" only for real accounts
|
|
98187
|
-
* re-creates the oracle the endpoint removed.
|
|
98188
|
-
*/
|
|
98189
|
-
requestMagicLink(handle, options) {
|
|
98190
|
-
this._makeRequest(handle, "/auth/magic-link", {
|
|
98191
|
-
method: "POST",
|
|
98192
|
-
content: { email: options.email, redirect: options.redirect || this._currentUrlWithoutAuthParams() },
|
|
98193
|
-
success: () => options.success(),
|
|
98194
|
-
error: (e) => options.error(e.error)
|
|
98195
|
-
});
|
|
98196
|
-
}
|
|
98197
|
-
// ── Not contract, and deliberately so ────────────────────────────────────
|
|
98198
|
-
/**
|
|
98199
|
-
* Write user-profile fields onto the signed-in user.
|
|
98200
|
-
*
|
|
98201
|
-
* Not one of the ten. It is the `Set User Properties` node's whole
|
|
98202
|
-
* implementation, and BCN-006's Desired State §3 makes it schema-driven across
|
|
98203
|
-
* five backends — which is step 6, not this pass. It moves with the wire
|
|
98204
|
-
* because leaving it behind would have left a second `_makeRequest` in
|
|
98205
|
-
* `userservice.ts`, and the entire claim of this move is that there is one.
|
|
98206
|
-
*/
|
|
98207
|
-
setUserProperties(handle, options) {
|
|
98208
|
-
const _cu = this.getCurrentUser(handle);
|
|
98209
|
-
if (_cu === void 0) {
|
|
98210
|
-
options.error("Nobody is signed in.");
|
|
98211
|
-
return;
|
|
98212
|
-
}
|
|
98213
|
-
{
|
|
98214
|
-
const propsToSave = this.serializeObject({ ...options.properties }, "_User");
|
|
98215
|
-
const _content = Object.assign(
|
|
98216
|
-
{},
|
|
98217
|
-
{ email: options.email, username: options.username },
|
|
98218
|
-
propsToSave
|
|
98219
|
-
);
|
|
98220
|
-
delete _content.emailVerified;
|
|
98221
|
-
delete _content.createdAt;
|
|
98222
|
-
delete _content.updatedAt;
|
|
98223
|
-
this._makeRequest(handle, "/users/" + _cu.objectId, {
|
|
98224
|
-
method: "PUT",
|
|
98225
|
-
content: _content,
|
|
98226
|
-
success: (response) => {
|
|
98227
|
-
Object.assign(_cu, _content);
|
|
98228
|
-
this.setSession(handle, _cu);
|
|
98229
|
-
options.success(response);
|
|
98230
|
-
},
|
|
98231
|
-
error: (e) => {
|
|
98232
|
-
options.error(e.error);
|
|
98233
|
-
}
|
|
98234
|
-
});
|
|
98235
|
-
}
|
|
98236
|
-
}
|
|
98237
|
-
/** The sign-in methods this backend offers — for rendering a set of buttons. */
|
|
98238
|
-
listAuthProviders(handle, options) {
|
|
98239
|
-
this._makeRequest(handle, "/auth/providers", {
|
|
98240
|
-
method: "GET",
|
|
98241
|
-
success: (response) => options.success(response),
|
|
98242
|
-
error: (e) => options.error(e.error)
|
|
98243
|
-
});
|
|
98244
|
-
}
|
|
98245
|
-
// ── BAK-004 — the provider return leg ────────────────────────────────────
|
|
98246
|
-
/**
|
|
98247
|
-
* Look for a sign-in result in the current URL and act on it.
|
|
98248
|
-
*
|
|
98249
|
-
* Returns true when this page load IS a sign-in return, so the caller can skip
|
|
98250
|
-
* its ordinary stale-session validation.
|
|
98251
|
-
*
|
|
98252
|
-
* **Per backend, not contract.** BCN-006 step 5 is four different redirect
|
|
98253
|
-
* shapes — Parse `authData`, Directus SSO, Supabase, PocketBase
|
|
98254
|
-
* `auth-with-oauth2` — and this is the first of the four. What they have in
|
|
98255
|
-
* common is only the *outcome*: a session, established. That is where the
|
|
98256
|
-
* contract's surface is, and it is `signInWithProvider` plus a `loggedIn`.
|
|
98257
|
-
*/
|
|
98258
|
-
consumeAuthReturn(handle) {
|
|
98259
|
-
if (typeof window === "undefined" || !window.location) return false;
|
|
98260
|
-
let params;
|
|
98261
|
-
try {
|
|
98262
|
-
params = new URLSearchParams(window.location.search);
|
|
98263
|
-
} catch (e) {
|
|
98264
|
-
return false;
|
|
98265
|
-
}
|
|
98266
|
-
const code = params.get(HANDOFF_PARAM);
|
|
98267
|
-
const error = params.get(AUTH_ERROR_PARAM);
|
|
98268
|
-
if (!code && !error) return false;
|
|
98269
|
-
params.delete(HANDOFF_PARAM);
|
|
98270
|
-
params.delete(AUTH_ERROR_PARAM);
|
|
98271
|
-
this._stripAuthParamsFromUrl(params);
|
|
98272
|
-
if (error) {
|
|
98273
|
-
this.oauthReturn = { inProgress: false, succeeded: false, error };
|
|
98274
|
-
setTimeout(() => this.emitAuthEvent("oauthReturn", this.oauthReturn), 0);
|
|
98275
|
-
return true;
|
|
98276
|
-
}
|
|
98277
|
-
this.oauthReturn = { inProgress: true };
|
|
98278
|
-
this._makeRequest(handle, "/oauth/exchange", {
|
|
98279
|
-
method: "POST",
|
|
98280
|
-
content: { code },
|
|
98281
|
-
success: (response) => {
|
|
98282
|
-
this.setSession(handle, response);
|
|
98283
|
-
this.oauthReturn = {
|
|
98284
|
-
inProgress: false,
|
|
98285
|
-
succeeded: true,
|
|
98286
|
-
outcome: response.authOutcome,
|
|
98287
|
-
notice: response.authNotice || void 0
|
|
98288
|
-
};
|
|
98289
|
-
this.emitAuthEvent("oauthReturn", this.oauthReturn);
|
|
98290
|
-
this.emitAuthEvent("loggedIn", response);
|
|
98291
|
-
},
|
|
98292
|
-
error: (e) => {
|
|
98293
|
-
this.oauthReturn = {
|
|
98294
|
-
inProgress: false,
|
|
98295
|
-
succeeded: false,
|
|
98296
|
-
error: e && e.error || "Sign-in could not be completed."
|
|
98297
|
-
};
|
|
98298
|
-
this.emitAuthEvent("oauthReturn", this.oauthReturn);
|
|
98299
|
-
}
|
|
98300
|
-
});
|
|
98301
|
-
return true;
|
|
98302
|
-
}
|
|
98303
|
-
/** Rewrite the address bar without the sign-in parameters, keeping everything else. */
|
|
98304
|
-
_stripAuthParamsFromUrl(remaining) {
|
|
98305
|
-
if (!window.history || typeof window.history.replaceState !== "function") return;
|
|
98306
|
-
const query = remaining.toString();
|
|
98307
|
-
const cleaned = window.location.pathname + (query ? `?${query}` : "") + window.location.hash;
|
|
98308
|
-
try {
|
|
98309
|
-
window.history.replaceState(window.history.state, "", cleaned);
|
|
98310
|
-
} catch (e) {
|
|
98311
|
-
}
|
|
98312
|
-
}
|
|
98313
|
-
_currentUrlWithoutAuthParams() {
|
|
98314
|
-
const url = new URL(window.location.href);
|
|
98315
|
-
url.searchParams.delete(HANDOFF_PARAM);
|
|
98316
|
-
url.searchParams.delete(AUTH_ERROR_PARAM);
|
|
98317
|
-
return url.toString();
|
|
98318
|
-
}
|
|
98319
|
-
};
|
|
98320
|
-
}
|
|
98321
|
-
});
|
|
98322
|
-
|
|
98323
98480
|
// ../noodl-viewer-react/src/nodes/std-library/user/userservice.ts
|
|
98324
98481
|
var import_events2, import_runtime14, import_cloudstore2, UserService, _instance, userservice_default;
|
|
98325
98482
|
var init_userservice = __esm({
|
|
@@ -98865,44 +99022,20 @@ var signup_exports = {};
|
|
|
98865
99022
|
__export(signup_exports, {
|
|
98866
99023
|
default: () => signup_default
|
|
98867
99024
|
});
|
|
98868
|
-
function updatePorts6(nodeId,
|
|
98869
|
-
const
|
|
98870
|
-
|
|
98871
|
-
|
|
98872
|
-
|
|
98873
|
-
|
|
98874
|
-
const _ignoreKeys = ["authData", "password", "username", "createdAt", "updatedAt", "emailVerified", "email", "ACL"];
|
|
98875
|
-
for (const key in props) {
|
|
98876
|
-
if (_ignoreKeys.indexOf(key) !== -1) continue;
|
|
98877
|
-
const p = props[key];
|
|
98878
|
-
if (ports.find((_p) => _p.name === key)) continue;
|
|
98879
|
-
if (p.type === "Relation") {
|
|
98880
|
-
} else {
|
|
98881
|
-
const _typeMap = {
|
|
98882
|
-
String: "string",
|
|
98883
|
-
Boolean: "boolean",
|
|
98884
|
-
Number: "number",
|
|
98885
|
-
Date: "date"
|
|
98886
|
-
};
|
|
98887
|
-
ports.push({
|
|
98888
|
-
type: {
|
|
98889
|
-
name: _typeMap[p.type] ? _typeMap[p.type] : "*"
|
|
98890
|
-
},
|
|
98891
|
-
plug: "input",
|
|
98892
|
-
group: "Properties",
|
|
98893
|
-
name: "prop-" + key,
|
|
98894
|
-
displayName: key
|
|
98895
|
-
});
|
|
98896
|
-
}
|
|
98897
|
-
}
|
|
98898
|
-
}
|
|
98899
|
-
}
|
|
98900
|
-
editorConnection.sendDynamicPorts(nodeId, ports);
|
|
99025
|
+
function updatePorts6(nodeId, editorConnection, graphModel) {
|
|
99026
|
+
const ctx = userSchemaContext(graphModel, {});
|
|
99027
|
+
const ignore = isParseWireContext(ctx) ? USER_INPUT_IGNORE_PARSE_BROWSER : USER_INPUT_IGNORE_REST;
|
|
99028
|
+
sendSchemaPorts(editorConnection, nodeId, userPropertyPorts(ctx, { plug: "input", ignore }), {
|
|
99029
|
+
staticPorts: staticPortNames(SignUpNodeDefinition)
|
|
99030
|
+
});
|
|
98901
99031
|
}
|
|
98902
99032
|
var SIGN_UP_ERROR_CODE, SignUpNodeDefinition, SignUpModule, signup_default;
|
|
98903
99033
|
var init_signup = __esm({
|
|
98904
99034
|
"../noodl-viewer-react/src/nodes/std-library/user/signup.ts"() {
|
|
98905
99035
|
"use strict";
|
|
99036
|
+
init_record_ports();
|
|
99037
|
+
init_schema_ports();
|
|
99038
|
+
init_user_ports();
|
|
98906
99039
|
init_outcome();
|
|
98907
99040
|
init_userservice();
|
|
98908
99041
|
SIGN_UP_ERROR_CODE = "user/sign-up-failed";
|
|
@@ -99040,23 +99173,11 @@ var init_signup = __esm({
|
|
|
99040
99173
|
return;
|
|
99041
99174
|
}
|
|
99042
99175
|
function _managePortsForNode(node) {
|
|
99043
|
-
updatePorts6(
|
|
99044
|
-
|
|
99045
|
-
|
|
99046
|
-
|
|
99047
|
-
|
|
99048
|
-
);
|
|
99049
|
-
node.on("parameterUpdated", function() {
|
|
99050
|
-
updatePorts6(
|
|
99051
|
-
node.id,
|
|
99052
|
-
node.parameters,
|
|
99053
|
-
editorConnection,
|
|
99054
|
-
graphModel.getMetaData("systemCollections")
|
|
99055
|
-
);
|
|
99056
|
-
});
|
|
99057
|
-
graphModel.on("metadataChanged.systemCollections", function(data) {
|
|
99058
|
-
updatePorts6(node.id, node.parameters, editorConnection, data);
|
|
99059
|
-
});
|
|
99176
|
+
const rebuild2 = () => updatePorts6(node.id, editorConnection, graphModel);
|
|
99177
|
+
rebuild2();
|
|
99178
|
+
graphModel.on("metadataChanged.systemCollections", rebuild2);
|
|
99179
|
+
graphModel.on("metadataChanged.dbCollections", rebuild2);
|
|
99180
|
+
graphModel.on("metadataChanged.backendServices", rebuild2);
|
|
99060
99181
|
}
|
|
99061
99182
|
graphModel.on("editorImportComplete", () => {
|
|
99062
99183
|
graphModel.on("nodeAdded.net.noodl.user.SignUp", function(node) {
|
|
@@ -100237,6 +100358,7 @@ __export(cloudfunction_exports, {
|
|
|
100237
100358
|
default: () => cloudfunction_default
|
|
100238
100359
|
});
|
|
100239
100360
|
function _makeRequest2(path8, options) {
|
|
100361
|
+
options = holdOptionsForWrite(options);
|
|
100240
100362
|
const xhr = new XMLHttpRequest();
|
|
100241
100363
|
xhr.onreadystatechange = function() {
|
|
100242
100364
|
if (xhr.readyState === 4) {
|
|
@@ -100265,6 +100387,7 @@ var init_cloudfunction = __esm({
|
|
|
100265
100387
|
import_runtime15 = __toESM(require_noodl_runtime());
|
|
100266
100388
|
import_cloudstore3 = __toESM(require_cloudstore());
|
|
100267
100389
|
init_SessionStore();
|
|
100390
|
+
init_pressguard();
|
|
100268
100391
|
CloudFunctionNode2 = {
|
|
100269
100392
|
name: "Cloud Function",
|
|
100270
100393
|
category: "Cloud Services",
|
|
@@ -112336,7 +112459,7 @@ var require_package = __commonJS({
|
|
|
112336
112459
|
"package.json"(exports2, module2) {
|
|
112337
112460
|
module2.exports = {
|
|
112338
112461
|
name: "@nodegx/preview",
|
|
112339
|
-
version: "0.2.
|
|
112462
|
+
version: "0.2.6",
|
|
112340
112463
|
description: "Standalone live-preview harness: renders a NodeGX (OpenNoodl) v2 project in a browser with no editor process, and reloads it when the files on disk change.",
|
|
112341
112464
|
license: "GPL-3.0-only",
|
|
112342
112465
|
homepage: "https://nodegx.io",
|
|
@@ -167046,11 +167169,12 @@ var node_catalog_default = {
|
|
|
167046
167169
|
],
|
|
167047
167170
|
items: [
|
|
167048
167171
|
"nothing handed (undefined): the list it has stays",
|
|
167172
|
+
"the value is still the placed node's seed and the list does not offer it: the list is kept, and the value is cleared to '' and sent",
|
|
167049
167173
|
"otherwise: the list is kept as handed and drawn at the next paint; the value stays, so a list handed again keeps the pick"
|
|
167050
167174
|
],
|
|
167051
167175
|
value: [
|
|
167052
167176
|
"null: ignored",
|
|
167053
|
-
"the value it already holds, as text: nothing",
|
|
167177
|
+
"the value it already holds, as text: nothing (it is no longer the seed)",
|
|
167054
167178
|
"a change: kept as text, Value follows, and the list selects it at the next paint if it names an option \u2014 Changed does not fire (only a person's pick fires it)"
|
|
167055
167179
|
],
|
|
167056
167180
|
mounted: [
|
|
@@ -179431,7 +179555,7 @@ var node_catalog_default = {
|
|
|
179431
179555
|
group: "Request",
|
|
179432
179556
|
plug: "output",
|
|
179433
179557
|
type: {
|
|
179434
|
-
name: "
|
|
179558
|
+
name: "string"
|
|
179435
179559
|
},
|
|
179436
179560
|
isSignal: false,
|
|
179437
179561
|
description: "Id of the user the session token resolved to, and blank for an unauthenticated request"
|
|
@@ -180657,8 +180781,8 @@ var CatalogIndex = class _CatalogIndex {
|
|
|
180657
180781
|
suggestPort(typeName2, plug, unknown, kind) {
|
|
180658
180782
|
const names = this.portNames(typeName2, plug);
|
|
180659
180783
|
const candidates = kind ? names.filter((name2) => {
|
|
180660
|
-
const
|
|
180661
|
-
return
|
|
180784
|
+
const own2 = this.portKind(typeName2, plug, name2);
|
|
180785
|
+
return own2 === void 0 || own2 === kind;
|
|
180662
180786
|
}) : names;
|
|
180663
180787
|
return nearest(unknown, candidates);
|
|
180664
180788
|
}
|
|
@@ -191036,7 +191160,15 @@ function projectModelFromLegacy(legacy) {
|
|
|
191036
191160
|
var fs3 = __toESM(require("fs"));
|
|
191037
191161
|
var path4 = __toESM(require("path"));
|
|
191038
191162
|
init_scriptfiles();
|
|
191039
|
-
var readJson = (file) =>
|
|
191163
|
+
var readJson = (file) => {
|
|
191164
|
+
const text2 = fs3.readFileSync(file, "utf8");
|
|
191165
|
+
try {
|
|
191166
|
+
return JSON.parse(text2);
|
|
191167
|
+
} catch (e) {
|
|
191168
|
+
const why = text2.trim() === "" ? "the file is empty, so it is not valid JSON" : e instanceof Error ? e.message : String(e);
|
|
191169
|
+
throw Object.assign(new Error(`${file.split(path4.sep).join("/")}: ${why}`), { projectFile: file });
|
|
191170
|
+
}
|
|
191171
|
+
};
|
|
191040
191172
|
function resolveTarget(target) {
|
|
191041
191173
|
const abs = path4.resolve(target);
|
|
191042
191174
|
if (!fs3.existsSync(abs)) throw new Error(`No such file or directory: ${abs}`);
|
|
@@ -191179,6 +191311,9 @@ function flatten3(roots) {
|
|
|
191179
191311
|
for (const root2 of roots) visit(root2, void 0);
|
|
191180
191312
|
return out;
|
|
191181
191313
|
}
|
|
191314
|
+
function recordedVisualRoots(list) {
|
|
191315
|
+
return Array.isArray(list) && list.length > 0 ? { visualRoots: list.filter((id) => typeof id === "string") } : {};
|
|
191316
|
+
}
|
|
191182
191317
|
function fromLegacyProject(project) {
|
|
191183
191318
|
const components = [];
|
|
191184
191319
|
for (const comp of project.components ?? []) {
|
|
@@ -191192,7 +191327,8 @@ function fromLegacyProject(project) {
|
|
|
191192
191327
|
components.push({
|
|
191193
191328
|
name: comp.name,
|
|
191194
191329
|
nodes: flatten3(graph.roots ?? []),
|
|
191195
|
-
connections
|
|
191330
|
+
connections,
|
|
191331
|
+
...recordedVisualRoots(graph.visualRoots)
|
|
191196
191332
|
});
|
|
191197
191333
|
}
|
|
191198
191334
|
return {
|
|
@@ -192036,6 +192172,7 @@ function cloudPortMeaning(type, plug) {
|
|
|
192036
192172
|
|
|
192037
192173
|
// ../noodl-editor/src/editor/src/validation/functionScriptUses.ts
|
|
192038
192174
|
init_scriptfiles();
|
|
192175
|
+
var FUNCTION_NODE_TYPE = "JavaScriptFunction";
|
|
192039
192176
|
|
|
192040
192177
|
// ../noodl-editor/src/editor/src/validation/functionPorts.ts
|
|
192041
192178
|
var SCRIPT_NODE_API_MEMBERS = [
|
|
@@ -192054,6 +192191,10 @@ var SCRIPT_DECLARATION = new RegExp(
|
|
|
192054
192191
|
)
|
|
192055
192192
|
);
|
|
192056
192193
|
|
|
192194
|
+
// ../noodl-editor/src/editor/src/validation/publicWriteDoor.ts
|
|
192195
|
+
var RECORD_WRITE_SCRIPT_MEMBERS = ["create", "save", "delete", "increment", "addRelation", "removeRelation"];
|
|
192196
|
+
var SCRIPT_WRITE_CALL = new RegExp(`\\bRecords\\s*\\.\\s*(${RECORD_WRITE_SCRIPT_MEMBERS.join("|")})\\s*\\(`);
|
|
192197
|
+
|
|
192057
192198
|
// ../noodl-editor/src/editor/src/validation/typedWordNotTranslated.ts
|
|
192058
192199
|
var HAS_LETTER = new RegExp("\\p{L}", "u");
|
|
192059
192200
|
|
|
@@ -192250,7 +192391,11 @@ var AUTHORED_BLOCKING_WARNINGS = /* @__PURE__ */ new Set([
|
|
|
192250
192391
|
// and **no `completed` wires at all**. `completed` is a rare port — authors
|
|
192251
192392
|
// reach for `done` — so the blast radius of making this blocking is small, and
|
|
192252
192393
|
// that is a measurement rather than a hope.
|
|
192253
|
-
"completed-commits-unchecked" /* CompletedCommitsUnchecked
|
|
192394
|
+
"completed-commits-unchecked" /* CompletedCommitsUnchecked */,
|
|
192395
|
+
// Bug P121-TWO003-SCRIPTCOMPILE — the runtime's own compile fails, so every Run fails. No benign
|
|
192396
|
+
// reading for a graph an agent just wrote; the write said nothing before, and the first person
|
|
192397
|
+
// to run the function got "That could not be done."
|
|
192398
|
+
"function-script-not-compiled" /* FunctionScriptNotCompiled */
|
|
192254
192399
|
]);
|
|
192255
192400
|
|
|
192256
192401
|
// ../noodl-editor/src/editor/src/validation/diagnosticExamples.ts
|
|
@@ -192379,6 +192524,17 @@ var DIAGNOSTIC_EXAMPLES = [
|
|
|
192379
192524
|
code: "function-trusts-a-field-the-caller-wrote" /* FunctionTrustsAFieldTheCallerWrote */,
|
|
192380
192525
|
examples: ["cloud-share-my-records-with-someone"],
|
|
192381
192526
|
why: "a cloud function that returns the records of the shares' owners, never a field the page wrote"
|
|
192527
|
+
},
|
|
192528
|
+
// P112 OWN-026 FIX-06 B — a group joined only through its owner's invitation, written only by a function.
|
|
192529
|
+
{
|
|
192530
|
+
code: "role-named-by-a-field-the-caller-wrote" /* RoleNamedByAFieldTheCallerWrote */,
|
|
192531
|
+
examples: ["cloud-members-can-edit-my-records"],
|
|
192532
|
+
why: "a cloud function that names the role from the invitation's owner, so an invitation only lets someone into its creator's group"
|
|
192533
|
+
},
|
|
192534
|
+
{
|
|
192535
|
+
code: "function-guards-an-open-collection" /* FunctionGuardsAnOpenCollection */,
|
|
192536
|
+
examples: ["cloud-members-can-edit-my-records"],
|
|
192537
|
+
why: `the records only a function creates, with the collection's create rule "nobody": the function runs as the system`
|
|
192382
192538
|
}
|
|
192383
192539
|
];
|
|
192384
192540
|
|
|
@@ -192569,6 +192725,9 @@ var unknownNodeType = {
|
|
|
192569
192725
|
}
|
|
192570
192726
|
};
|
|
192571
192727
|
|
|
192728
|
+
// ../noodl-editor/src/editor/src/validation/rules/nonexistentPort.ts
|
|
192729
|
+
init_renamed_ports();
|
|
192730
|
+
|
|
192572
192731
|
// ../noodl-editor/src/editor/src/views/panels/propertyeditor/propertyPanelTiers.ts
|
|
192573
192732
|
var ADVANCED_CSS_GROUPS = {
|
|
192574
192733
|
// ── plumbing ────────────────────────────────────────────────────────────────
|
|
@@ -192647,18 +192806,23 @@ function otherEndKind(catalog, nodeById, conn, plug) {
|
|
|
192647
192806
|
}
|
|
192648
192807
|
return portKindOfTypeName(other.instancePortTypes?.[port]);
|
|
192649
192808
|
}
|
|
192809
|
+
function renamedPort(type, port, plug) {
|
|
192810
|
+
const to = plug === "output" ? renamedOutput(type, port) : void 0;
|
|
192811
|
+
return to ? { to, sentence: ` It was renamed "${to}" in August 2026: wire "${to}".` } : void 0;
|
|
192812
|
+
}
|
|
192650
192813
|
function missingDrawnPort(catalog, nodeById, conn, component, node, port, plug, drawn) {
|
|
192651
192814
|
const names = [...drawn];
|
|
192652
192815
|
const tail = (name2) => name2.slice(name2.indexOf("-") + 1).toLowerCase();
|
|
192653
192816
|
const suffixed = names.filter((name2) => tail(name2) === port.toLowerCase() || tail(name2) === tail(port));
|
|
192654
|
-
const
|
|
192817
|
+
const renamed = renamedPort(node.type, port, plug);
|
|
192818
|
+
const suggestion = renamed && drawn.has(renamed.to) ? renamed.to : suffixed.length > 0 ? nearest(port, suffixed) ?? suffixed[0] : nearest(port, names);
|
|
192655
192819
|
const wireKind = otherEndKind(catalog, nodeById, conn, plug);
|
|
192656
192820
|
const fromProject = names.filter((name2) => !catalog.hasPort(node.type, plug, name2)).sort();
|
|
192657
192821
|
const alternatives = [.../* @__PURE__ */ new Set([...fromProject, ...availableAlternatives(catalog, node.type, plug, wireKind).filter((name2) => drawn.has(name2))])].slice(0, MAX_ALTERNATIVES3);
|
|
192658
192822
|
return {
|
|
192659
192823
|
code: "nonexistent-port" /* NonexistentPort */,
|
|
192660
192824
|
severity: "error",
|
|
192661
|
-
message: `${node.type} has no ${plug} named "${port}" with its settings in this project
|
|
192825
|
+
message: `${node.type} has no ${plug} named "${port}" with its settings in this project.` + (renamed && drawn.has(renamed.to) ? renamed.sentence : ""),
|
|
192662
192826
|
location: {
|
|
192663
192827
|
component,
|
|
192664
192828
|
nodeId: node.id,
|
|
@@ -192738,12 +192902,13 @@ var nonexistentPort = {
|
|
|
192738
192902
|
}
|
|
192739
192903
|
const wireKind = otherEndKind(catalog, nodeById, conn, plug);
|
|
192740
192904
|
const prefixed = missingPrefix ? missingPrefix + port : void 0;
|
|
192741
|
-
const
|
|
192905
|
+
const renamed = renamedPort(node.type, port, plug);
|
|
192906
|
+
const suggestion = renamed?.to ?? catalog.suggestPort(node.type, plug, port, wireKind) ?? prefixed;
|
|
192742
192907
|
const alternatives = availableAlternatives(catalog, node.type, plug, wireKind);
|
|
192743
192908
|
out.push({
|
|
192744
192909
|
code: "nonexistent-port" /* NonexistentPort */,
|
|
192745
192910
|
severity: "error",
|
|
192746
|
-
message: `${node.type} has no ${plug} named "${port}".` + (prefixed ? ` Its other ${plug}s exist only as "${missingPrefix}<name>", so a name without the prefix is never made and nothing goes through this wire. If "${port}" is ${cloudPortMeaning(node.type, plug)}, wire "${prefixed}".` : ""),
|
|
192911
|
+
message: `${node.type} has no ${plug} named "${port}".` + (renamed?.sentence ?? "") + (prefixed ? ` Its other ${plug}s exist only as "${missingPrefix}<name>", so a name without the prefix is never made and nothing goes through this wire. If "${port}" is ${cloudPortMeaning(node.type, plug)}, wire "${prefixed}".` : ""),
|
|
192747
192912
|
location: {
|
|
192748
192913
|
component: component.name,
|
|
192749
192914
|
nodeId: node.id,
|
|
@@ -192946,6 +193111,7 @@ var detachedPageContent = {
|
|
|
192946
193111
|
};
|
|
192947
193112
|
|
|
192948
193113
|
// ../noodl-editor/src/editor/src/validation/rules/invalidHierarchy.ts
|
|
193114
|
+
var RECORDED_VISUAL_ROOT = { allowAsChild: true, category: "Visual" };
|
|
192949
193115
|
function hierarchyTyper(ctx) {
|
|
192950
193116
|
const byName = /* @__PURE__ */ new Map();
|
|
192951
193117
|
for (const c of ctx.project.components) {
|
|
@@ -192965,8 +193131,9 @@ function hierarchyTyper(ctx) {
|
|
|
192965
193131
|
const childIds = new Set(component.nodes.flatMap((n) => n.children));
|
|
192966
193132
|
const roots = component.nodes.filter((n) => n.parent === void 0 && !childIds.has(n.id));
|
|
192967
193133
|
const known = (n) => typeOf(n.type);
|
|
193134
|
+
const rootType = (n) => known(n) ?? (component.visualRoots?.includes(n.id) ? RECORDED_VISUAL_ROOT : void 0);
|
|
192968
193135
|
const derived = componentHierarchyType(
|
|
192969
|
-
roots.map(
|
|
193136
|
+
roots.map(rootType).filter((t) => !!t),
|
|
192970
193137
|
component.nodes.map(known).filter((t) => !!t)
|
|
192971
193138
|
);
|
|
192972
193139
|
inFlight.delete(typeName2);
|
|
@@ -193837,6 +194004,123 @@ var settingsDiagnostic = {
|
|
|
193837
194004
|
}
|
|
193838
194005
|
};
|
|
193839
194006
|
|
|
194007
|
+
// ../noodl-editor/src/editor/src/validation/rules/functionScriptNotCompiled.ts
|
|
194008
|
+
var CODE_PREFIX = "const Script = (typeof Node !== 'undefined')?Node:undefined;\n";
|
|
194009
|
+
var PARAMS2 = ["Inputs", "Outputs", "Noodl", "Component", "Scripts"];
|
|
194010
|
+
function functionScriptCompileError(script) {
|
|
194011
|
+
try {
|
|
194012
|
+
const AsyncFunction = Object.getPrototypeOf(async function() {
|
|
194013
|
+
}).constructor;
|
|
194014
|
+
new AsyncFunction(...PARAMS2, CODE_PREFIX + script);
|
|
194015
|
+
return void 0;
|
|
194016
|
+
} catch (e) {
|
|
194017
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
194018
|
+
const line = syntaxErrorLine(script);
|
|
194019
|
+
return line === void 0 ? { message } : { message, line };
|
|
194020
|
+
}
|
|
194021
|
+
}
|
|
194022
|
+
function syntaxErrorLine(script) {
|
|
194023
|
+
const file = "nodegx-function-script";
|
|
194024
|
+
try {
|
|
194025
|
+
const vm = typeof require === "function" ? require("vm") : void 0;
|
|
194026
|
+
if (!vm?.Script) return void 0;
|
|
194027
|
+
new vm.Script(`(async function (${PARAMS2.join(", ")}) {
|
|
194028
|
+
${script}
|
|
194029
|
+
})`, { filename: file });
|
|
194030
|
+
} catch (e) {
|
|
194031
|
+
const stack = e && typeof e === "object" ? e.stack : void 0;
|
|
194032
|
+
const match = typeof stack === "string" ? new RegExp(`${file}:(\\d+)`).exec(stack) : null;
|
|
194033
|
+
if (match) return Math.max(1, Number(match[1]) - 1);
|
|
194034
|
+
}
|
|
194035
|
+
return void 0;
|
|
194036
|
+
}
|
|
194037
|
+
var functionScriptNotCompiled = {
|
|
194038
|
+
code: "function-script-not-compiled" /* FunctionScriptNotCompiled */,
|
|
194039
|
+
description: "A Function's script does not compile, so the Function can never run.",
|
|
194040
|
+
defaultEnabled: true,
|
|
194041
|
+
run(ctx) {
|
|
194042
|
+
const out = [];
|
|
194043
|
+
for (const { component } of ctx.components) {
|
|
194044
|
+
for (const node of component.nodes) {
|
|
194045
|
+
if (node.type !== FUNCTION_NODE_TYPE) continue;
|
|
194046
|
+
const script = node.parameters?.functionScript;
|
|
194047
|
+
if (typeof script !== "string" || script.trim() === "") continue;
|
|
194048
|
+
const error = functionScriptCompileError(script);
|
|
194049
|
+
if (!error) continue;
|
|
194050
|
+
const name2 = node.label ? `"${node.label}"` : "This Function";
|
|
194051
|
+
out.push({
|
|
194052
|
+
code: "function-script-not-compiled" /* FunctionScriptNotCompiled */,
|
|
194053
|
+
severity: "warning",
|
|
194054
|
+
message: `${name2}'s script does not compile${error.line !== void 0 ? ` (line ${error.line})` : ""}: ${error.message}. It can never run: every Run fails with function/script-not-compiled. Fix the script; a regular expression or URL written inside a template literal loses its backslashes, so \`\\/\\/\` arrives as \`//\`, which starts a comment.`,
|
|
194055
|
+
location: {
|
|
194056
|
+
component: component.name,
|
|
194057
|
+
nodeId: node.id,
|
|
194058
|
+
nodeType: node.type,
|
|
194059
|
+
nodeLabel: node.label,
|
|
194060
|
+
port: "functionScript"
|
|
194061
|
+
}
|
|
194062
|
+
});
|
|
194063
|
+
}
|
|
194064
|
+
}
|
|
194065
|
+
return out;
|
|
194066
|
+
}
|
|
194067
|
+
};
|
|
194068
|
+
|
|
194069
|
+
// ../noodl-editor/src/editor/src/validation/rules/functionNeverReruns.ts
|
|
194070
|
+
var RUN_ON_CHANGE_PREFIX3 = "runOnChange-";
|
|
194071
|
+
var functionNeverReruns = {
|
|
194072
|
+
code: "function-never-reruns" /* FunctionNeverReruns */,
|
|
194073
|
+
description: "Nothing re-runs a node when its inputs change: its control signal is unwired and every wired input is set not to run on change.",
|
|
194074
|
+
defaultEnabled: true,
|
|
194075
|
+
run(ctx) {
|
|
194076
|
+
const out = [];
|
|
194077
|
+
const { catalog } = ctx;
|
|
194078
|
+
for (const { component } of ctx.components) {
|
|
194079
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
194080
|
+
for (const c of component.connections) {
|
|
194081
|
+
const list = incoming.get(c.toId);
|
|
194082
|
+
if (list) list.push(c);
|
|
194083
|
+
else incoming.set(c.toId, [c]);
|
|
194084
|
+
}
|
|
194085
|
+
for (const node of component.nodes) {
|
|
194086
|
+
const isFunction2 = node.type === FUNCTION_NODE_TYPE;
|
|
194087
|
+
if (!isFunction2 && !catalog.isRunOnValueChangeFamily(node.type)) continue;
|
|
194088
|
+
const inbound = incoming.get(node.id) ?? [];
|
|
194089
|
+
if (inbound.length === 0) continue;
|
|
194090
|
+
if (inbound.some((c) => catalog.getPort(node.type, "input", c.toProperty)?.isSignal)) continue;
|
|
194091
|
+
const governed = [
|
|
194092
|
+
...new Set(
|
|
194093
|
+
inbound.map((c) => c.toProperty).filter(
|
|
194094
|
+
(port) => isFunction2 ? port.startsWith("in-") : !!catalog.getPort(node.type, "input", RUN_ON_CHANGE_PREFIX3 + port)
|
|
194095
|
+
)
|
|
194096
|
+
)
|
|
194097
|
+
];
|
|
194098
|
+
if (governed.length === 0) continue;
|
|
194099
|
+
const params = node.parameters ?? {};
|
|
194100
|
+
if (!governed.every((port) => params[RUN_ON_CHANGE_PREFIX3 + port] === false)) continue;
|
|
194101
|
+
const name2 = node.label ? `"${node.label}"` : isFunction2 ? "This Function" : "This node";
|
|
194102
|
+
const shown = governed.map((p) => `"${isFunction2 ? p.slice("in-".length) : p}"`).join(", ");
|
|
194103
|
+
out.push({
|
|
194104
|
+
code: "function-never-reruns" /* FunctionNeverReruns */,
|
|
194105
|
+
severity: "warning",
|
|
194106
|
+
message: `Nothing re-runs ${name2} when its inputs change: Run is not wired, and every wired input (${shown}) has Run On Value Change unticked. ` + (isFunction2 ? "It runs once when it loads, and a new value on any of them never runs it again. " : "") + "Wire Run to what should start it, or tick Run On Value Change on the input whose new value should run it.",
|
|
194107
|
+
location: {
|
|
194108
|
+
component: component.name,
|
|
194109
|
+
nodeId: node.id,
|
|
194110
|
+
nodeType: node.type,
|
|
194111
|
+
nodeLabel: node.label,
|
|
194112
|
+
port: RUN_ON_CHANGE_PREFIX3 + governed[0],
|
|
194113
|
+
plug: "input"
|
|
194114
|
+
},
|
|
194115
|
+
suggestion: `${RUN_ON_CHANGE_PREFIX3}${governed[0]}: true`,
|
|
194116
|
+
alternatives: governed.map((p) => `${RUN_ON_CHANGE_PREFIX3}${p}: true`)
|
|
194117
|
+
});
|
|
194118
|
+
}
|
|
194119
|
+
}
|
|
194120
|
+
return out;
|
|
194121
|
+
}
|
|
194122
|
+
};
|
|
194123
|
+
|
|
193840
194124
|
// ../noodl-editor/src/editor/src/validation/rules/index.ts
|
|
193841
194125
|
var ALL_RULES = [
|
|
193842
194126
|
duplicateNodeId,
|
|
@@ -193888,6 +194172,11 @@ var ALL_RULES = [
|
|
|
193888
194172
|
// the first fires on `prep` and never on the `RunTasks` carrying the defect,
|
|
193889
194173
|
// so this covers a hole in it rather than repeating it.
|
|
193890
194174
|
completedCommitsUnchecked,
|
|
194175
|
+
// P121 bugs SCRIPTCOMPILE / NEVERRUNS — a Function that can never run, and one that never
|
|
194176
|
+
// re-runs: breakage of the graph's behaviour, so beside the outcome rules and before the
|
|
194177
|
+
// arrangement ones.
|
|
194178
|
+
functionScriptNotCompiled,
|
|
194179
|
+
functionNeverReruns,
|
|
193891
194180
|
repeatedSiblingSubtree,
|
|
193892
194181
|
// DEF-025 — beside `repeatedSiblingSubtree` because both read the visual
|
|
193893
194182
|
// tree's arrangement rather than wires: that one asks whether siblings
|
|
@@ -194805,7 +195094,7 @@ var PreviewServer = class {
|
|
|
194805
195094
|
if (!bundle) return this.notFound(res);
|
|
194806
195095
|
return this.sendDynamic(res, bundle, "application/json; charset=utf-8");
|
|
194807
195096
|
}
|
|
194808
|
-
if (pathname === "/nodegx-config.json") return this.
|
|
195097
|
+
if (pathname === "/nodegx-config.json") return this.sendDynamic(res, "{}", "application/json; charset=utf-8");
|
|
194809
195098
|
const asset = pathname.slice(1);
|
|
194810
195099
|
if (DEPLOY_ASSETS.includes(asset)) {
|
|
194811
195100
|
return this.sendFile(req, res, deployAssetPath(asset));
|