@agiledigital/pingone-aic-script-tester 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/LICENSE-APACHE +201 -0
  2. package/LICENSE-MIT +21 -0
  3. package/README.md +274 -0
  4. package/dist/bin/fetch-jar.d.ts +2 -0
  5. package/dist/bin/fetch-jar.js +13 -0
  6. package/dist/bin/pull-profile.d.ts +2 -0
  7. package/dist/bin/pull-profile.js +40 -0
  8. package/dist/bin/show-log.d.ts +2 -0
  9. package/dist/bin/show-log.js +31 -0
  10. package/dist/classes/.complete +12 -0
  11. package/dist/classes/AmClassShutter.class +0 -0
  12. package/dist/classes/AmContextFactory$ObservedContext.class +0 -0
  13. package/dist/classes/AmContextFactory.class +0 -0
  14. package/dist/classes/AmScopes.class +0 -0
  15. package/dist/classes/HostOps.class +0 -0
  16. package/dist/classes/JsValues.class +0 -0
  17. package/dist/classes/Json$Parser.class +0 -0
  18. package/dist/classes/Json.class +0 -0
  19. package/dist/classes/LanguageVersions.class +0 -0
  20. package/dist/classes/Runner.class +0 -0
  21. package/dist/classes/ScriptContextScope.class +0 -0
  22. package/dist/src/aic/callbacks.d.ts +35 -0
  23. package/dist/src/aic/callbacks.js +130 -0
  24. package/dist/src/aic/conform.d.ts +90 -0
  25. package/dist/src/aic/conform.js +193 -0
  26. package/dist/src/aic/constants.d.ts +13 -0
  27. package/dist/src/aic/constants.js +13 -0
  28. package/dist/src/aic/diff.d.ts +25 -0
  29. package/dist/src/aic/diff.js +201 -0
  30. package/dist/src/aic/emit-journey.d.ts +64 -0
  31. package/dist/src/aic/emit-journey.js +254 -0
  32. package/dist/src/aic/emit-result.d.ts +10 -0
  33. package/dist/src/aic/emit-result.js +39 -0
  34. package/dist/src/aic/emit-session.d.ts +26 -0
  35. package/dist/src/aic/emit-session.js +132 -0
  36. package/dist/src/aic/emit-subject.d.ts +40 -0
  37. package/dist/src/aic/emit-subject.js +210 -0
  38. package/dist/src/aic/file-lease.d.ts +35 -0
  39. package/dist/src/aic/file-lease.js +543 -0
  40. package/dist/src/aic/http.d.ts +21 -0
  41. package/dist/src/aic/http.js +127 -0
  42. package/dist/src/aic/idm.d.ts +10 -0
  43. package/dist/src/aic/idm.js +112 -0
  44. package/dist/src/aic/index.d.ts +35 -0
  45. package/dist/src/aic/index.js +21 -0
  46. package/dist/src/aic/js.d.ts +8 -0
  47. package/dist/src/aic/js.js +11 -0
  48. package/dist/src/aic/lease-identity.d.ts +38 -0
  49. package/dist/src/aic/lease-identity.js +72 -0
  50. package/dist/src/aic/lease-lock.d.ts +45 -0
  51. package/dist/src/aic/lease-lock.js +173 -0
  52. package/dist/src/aic/managed.d.ts +28 -0
  53. package/dist/src/aic/managed.js +199 -0
  54. package/dist/src/aic/provider.d.ts +156 -0
  55. package/dist/src/aic/provider.js +416 -0
  56. package/dist/src/aic/record.d.ts +28 -0
  57. package/dist/src/aic/record.js +183 -0
  58. package/dist/src/aic/resource-snapshot.d.ts +12 -0
  59. package/dist/src/aic/resource-snapshot.js +116 -0
  60. package/dist/src/aic/run.d.ts +102 -0
  61. package/dist/src/aic/run.js +450 -0
  62. package/dist/src/aic/tenant.d.ts +107 -0
  63. package/dist/src/aic/tenant.js +307 -0
  64. package/dist/src/aic/trace.d.ts +25 -0
  65. package/dist/src/aic/trace.js +56 -0
  66. package/dist/src/aic/txid.d.ts +11 -0
  67. package/dist/src/aic/txid.js +25 -0
  68. package/dist/src/aic/unsupported.d.ts +15 -0
  69. package/dist/src/aic/unsupported.js +60 -0
  70. package/dist/src/bindings/allowlist.d.ts +42 -0
  71. package/dist/src/bindings/allowlist.js +62 -0
  72. package/dist/src/bindings/harvest.d.ts +7 -0
  73. package/dist/src/bindings/harvest.js +137 -0
  74. package/dist/src/bindings/index.d.ts +4 -0
  75. package/dist/src/bindings/index.js +3 -0
  76. package/dist/src/bindings/preamble.d.ts +23 -0
  77. package/dist/src/bindings/preamble.js +36 -0
  78. package/dist/src/bindings/run.d.ts +33 -0
  79. package/dist/src/bindings/run.js +55 -0
  80. package/dist/src/case/equal.d.ts +2 -0
  81. package/dist/src/case/equal.js +40 -0
  82. package/dist/src/case/index.d.ts +5 -0
  83. package/dist/src/case/index.js +4 -0
  84. package/dist/src/case/portable.d.ts +10 -0
  85. package/dist/src/case/portable.js +28 -0
  86. package/dist/src/case/session.d.ts +34 -0
  87. package/dist/src/case/session.js +66 -0
  88. package/dist/src/case/state.d.ts +4 -0
  89. package/dist/src/case/state.js +47 -0
  90. package/dist/src/case/types.d.ts +266 -0
  91. package/dist/src/case/types.js +106 -0
  92. package/dist/src/case/util.d.ts +7 -0
  93. package/dist/src/case/util.js +115 -0
  94. package/dist/src/case/validate.d.ts +8 -0
  95. package/dist/src/case/validate.js +463 -0
  96. package/dist/src/case/verdict.d.ts +6 -0
  97. package/dist/src/case/verdict.js +810 -0
  98. package/dist/src/diagnostics.d.ts +7 -0
  99. package/dist/src/diagnostics.js +5 -0
  100. package/dist/src/emit-dts.d.ts +2 -0
  101. package/dist/src/emit-dts.js +82 -0
  102. package/dist/src/emit-js.d.ts +3 -0
  103. package/dist/src/emit-js.js +149 -0
  104. package/dist/src/harness/failures.d.ts +26 -0
  105. package/dist/src/harness/failures.js +113 -0
  106. package/dist/src/harness/idm.d.ts +12 -0
  107. package/dist/src/harness/idm.js +44 -0
  108. package/dist/src/harness/index.d.ts +11 -0
  109. package/dist/src/harness/index.js +6 -0
  110. package/dist/src/harness/lease.d.ts +136 -0
  111. package/dist/src/harness/lease.js +286 -0
  112. package/dist/src/harness/residue.d.ts +23 -0
  113. package/dist/src/harness/residue.js +73 -0
  114. package/dist/src/harness/show-log.d.ts +43 -0
  115. package/dist/src/harness/show-log.js +253 -0
  116. package/dist/src/harness/spec.d.ts +67 -0
  117. package/dist/src/harness/spec.js +189 -0
  118. package/dist/src/harness/step.d.ts +80 -0
  119. package/dist/src/harness/step.js +97 -0
  120. package/dist/src/harness/types.d.ts +100 -0
  121. package/dist/src/harness/types.js +1 -0
  122. package/dist/src/harness/vitest.d.ts +52 -0
  123. package/dist/src/harness/vitest.js +155 -0
  124. package/dist/src/idents.d.ts +4 -0
  125. package/dist/src/idents.js +42 -0
  126. package/dist/src/jvm.d.ts +124 -0
  127. package/dist/src/jvm.js +432 -0
  128. package/dist/src/load.d.ts +2 -0
  129. package/dist/src/load.js +104 -0
  130. package/dist/src/paths.d.ts +36 -0
  131. package/dist/src/paths.js +50 -0
  132. package/dist/src/profile/index.d.ts +5 -0
  133. package/dist/src/profile/index.js +3 -0
  134. package/dist/src/profile/normalise.d.ts +16 -0
  135. package/dist/src/profile/normalise.js +106 -0
  136. package/dist/src/profile/pull.d.ts +22 -0
  137. package/dist/src/profile/pull.js +36 -0
  138. package/dist/src/profile/seed.d.ts +11 -0
  139. package/dist/src/profile/seed.js +28 -0
  140. package/dist/src/profile/store.d.ts +13 -0
  141. package/dist/src/profile/store.js +60 -0
  142. package/dist/src/profile/types.d.ts +45 -0
  143. package/dist/src/profile/types.js +1 -0
  144. package/dist/src/profile/validate.d.ts +38 -0
  145. package/dist/src/profile/validate.js +129 -0
  146. package/dist/src/project.d.ts +37 -0
  147. package/dist/src/project.js +93 -0
  148. package/dist/src/protocol.d.ts +62 -0
  149. package/dist/src/protocol.js +68 -0
  150. package/dist/src/provider-module.d.ts +11 -0
  151. package/dist/src/provider-module.js +46 -0
  152. package/dist/src/runner.d.ts +39 -0
  153. package/dist/src/runner.js +337 -0
  154. package/dist/src/schema.d.ts +48 -0
  155. package/dist/src/schema.js +93 -0
  156. package/generated/scripted-decision-mocks.cjs +722 -0
  157. package/generated/scripted-decision-mocks.d.ts +626 -0
  158. package/generated/scripted-decision-next.json +3640 -0
  159. package/java/AmClassShutter.java +98 -0
  160. package/java/AmContextFactory.java +69 -0
  161. package/java/AmScopes.java +49 -0
  162. package/java/HostOps.java +180 -0
  163. package/java/JsValues.java +39 -0
  164. package/java/Json.java +441 -0
  165. package/java/LanguageVersions.java +55 -0
  166. package/java/Runner.java +289 -0
  167. package/java/ScriptContextScope.java +147 -0
  168. package/package.json +88 -0
  169. package/src/bindings/rhino/runtime.cjs +3021 -0
@@ -0,0 +1,289 @@
1
+ import java.io.BufferedReader;
2
+ import java.io.FileDescriptor;
3
+ import java.io.FileOutputStream;
4
+ import java.io.InputStreamReader;
5
+ import java.io.PrintStream;
6
+ import java.nio.charset.Charset;
7
+ import java.nio.charset.StandardCharsets;
8
+ import java.util.LinkedHashMap;
9
+ import java.util.List;
10
+ import java.util.Locale;
11
+ import java.util.Map;
12
+ import java.util.TimeZone;
13
+ import javax.script.ScriptContext;
14
+ import javax.script.SimpleScriptContext;
15
+ import org.mozilla.javascript.Context;
16
+ import org.mozilla.javascript.EvaluatorException;
17
+ import org.mozilla.javascript.RhinoException;
18
+ import org.mozilla.javascript.Script;
19
+ import org.mozilla.javascript.Scriptable;
20
+ import org.mozilla.javascript.ScriptableObject;
21
+
22
+ /**
23
+ * Long-lived JVM speaking line-delimited JSON on stdin/stdout. One process,
24
+ * many jobs, a fresh {@link ScriptContextScope} per job. Anything the runner
25
+ * itself needs to say goes to stderr.
26
+ *
27
+ * <pre>
28
+ * java -cp rhino.jar:classes Runner
29
+ * </pre>
30
+ */
31
+ public final class Runner {
32
+
33
+ /** Harness default so a missing timeout cannot hang the process. AM's default is 0 (no timeout). */
34
+ static final long DEFAULT_TIMEOUT_MS = 10_000L;
35
+
36
+ static final PrintStream OUT =
37
+ new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8);
38
+ static final PrintStream ERR =
39
+ new PrintStream(new FileOutputStream(FileDescriptor.err), true, StandardCharsets.UTF_8);
40
+
41
+ public static void main(String[] args) throws Exception {
42
+ final AmContextFactory factory = new AmContextFactory();
43
+ ERR.println("rhino-local-runner ready " + Json.stringify(environment(factory)));
44
+ final BufferedReader in =
45
+ new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
46
+ String line;
47
+ while ((line = in.readLine()) != null) {
48
+ if (line.isEmpty()) {
49
+ continue;
50
+ }
51
+ handleLine(factory, line);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * What this JVM would make of a script that looked at its surroundings. The
57
+ * client refuses a JVM whose answers differ from the AM image's, because a
58
+ * host that defaulted to its own timezone or locale would pass a date-shaped
59
+ * test locally that fails on the tenant.
60
+ */
61
+ static Map<String, Object> environment(AmContextFactory factory) {
62
+ final Map<String, Object> env = new LinkedHashMap<String, Object>();
63
+ env.put("javaFeature", Integer.valueOf(Runtime.version().feature()));
64
+ env.put("javaVersion", Runtime.version().toString());
65
+ env.put("javaVendorVersion", System.getProperty("java.vendor.version"));
66
+ env.put("timezone", TimeZone.getDefault().getID());
67
+ env.put("locale", Locale.getDefault().toLanguageTag());
68
+ env.put("charset", Charset.defaultCharset().name());
69
+ final Context cx = factory.enterContext();
70
+ try {
71
+ env.put("rhino", cx.getImplementationVersion());
72
+ } finally {
73
+ Context.exit();
74
+ }
75
+ return env;
76
+ }
77
+
78
+ static void handleLine(AmContextFactory factory, String line) {
79
+ final Object parsed;
80
+ try {
81
+ parsed = Json.parse(line);
82
+ } catch (RuntimeException e) {
83
+ ERR.println("rhino-local-runner: skipping unparseable line: " + e.getMessage());
84
+ return;
85
+ }
86
+ final Map<String, Object> job;
87
+ try {
88
+ job = Json.asObject(parsed, "job");
89
+ } catch (RuntimeException e) {
90
+ ERR.println("rhino-local-runner: skipping non-object job: " + e.getMessage());
91
+ return;
92
+ }
93
+ final Object idRaw = job.get("id");
94
+ if (!(idRaw instanceof String) || ((String) idRaw).isEmpty()) {
95
+ ERR.println("rhino-local-runner: skipping job with no string id");
96
+ return;
97
+ }
98
+ final String id = (String) idRaw;
99
+ try {
100
+ if (Json.optionalBoolean(job, "shutdown", false)
101
+ || "shutdown".equals(Json.optionalString(job, "op"))) {
102
+ write(response(id, "ok", JsValues.of(Scriptable.NOT_FOUND), null));
103
+ OUT.flush();
104
+ System.exit(0);
105
+ return;
106
+ }
107
+ write(evalJob(factory, id, job));
108
+ } catch (Throwable t) {
109
+ write(errorResponse(id, "runtime_error", t, null, -1, -1, null));
110
+ }
111
+ }
112
+
113
+ static Map<String, Object> evalJob(
114
+ AmContextFactory factory, String id, Map<String, Object> job) {
115
+ final String source = Json.optionalString(job, "source");
116
+ if (source == null) {
117
+ return errorResponse(
118
+ id,
119
+ "protocol_error",
120
+ new IllegalArgumentException("job is missing source"),
121
+ null,
122
+ -1,
123
+ -1,
124
+ null);
125
+ }
126
+ final String sourceName;
127
+ final String requestedName = Json.optionalString(job, "sourceName");
128
+ if (requestedName != null && !requestedName.isEmpty()) {
129
+ sourceName = requestedName;
130
+ } else {
131
+ sourceName = id;
132
+ }
133
+ final int languageVersion;
134
+ try {
135
+ languageVersion = LanguageVersions.parse(job.get("languageVersion"));
136
+ } catch (RuntimeException e) {
137
+ return errorResponse(id, "protocol_error", e, sourceName, -1, -1, null);
138
+ }
139
+ final long timeoutMs = Json.optionalLong(job, "timeoutMs", DEFAULT_TIMEOUT_MS);
140
+ final String preamble = Json.optionalString(job, "preamble");
141
+ final String preambleName;
142
+ final String requestedPreamble = Json.optionalString(job, "preambleName");
143
+ if (requestedPreamble != null && !requestedPreamble.isEmpty()) {
144
+ preambleName = requestedPreamble;
145
+ } else {
146
+ preambleName = "<preamble>";
147
+ }
148
+
149
+ final List<String> classAllowList;
150
+ try {
151
+ classAllowList = Json.optionalStringList(job, "classAllowList");
152
+ } catch (RuntimeException e) {
153
+ return errorResponse(id, "protocol_error", e, sourceName, -1, -1, null);
154
+ }
155
+
156
+ final Context cx = factory.enterContext();
157
+ try {
158
+ cx.setLanguageVersion(languageVersion);
159
+ // No list means no shutter, which is the pre-shutter behaviour: every
160
+ // Java name resolves. Callers that mean to reproduce a script context
161
+ // pass that context's allowLists.
162
+ if (classAllowList != null) {
163
+ cx.setClassShutter(AmClassShutter.of(classAllowList));
164
+ }
165
+ if (cx instanceof AmContextFactory.ObservedContext) {
166
+ ((AmContextFactory.ObservedContext) cx).timeoutMs = timeoutMs;
167
+ }
168
+ final SimpleScriptContext scriptContext = AmScopes.newEngineContext(sourceName);
169
+ injectGlobals(scriptContext, job.get("globals"));
170
+ final Scriptable scope = AmScopes.makeScriptable(cx, scriptContext);
171
+
172
+ if (preamble != null && !preamble.isEmpty()) {
173
+ try {
174
+ final String hostOpName = "__rhinoLocalHostOp";
175
+ HostOps hostOps = new HostOps();
176
+ hostOps.setParentScope(scope);
177
+ hostOps.setPrototype(ScriptableObject.getFunctionPrototype(scope));
178
+ ScriptableObject.putProperty(scope, hostOpName, hostOps);
179
+ try {
180
+ Script preambleScript = cx.compileString(preamble, preambleName, 1, null);
181
+ preambleScript.exec(cx, scope);
182
+ } finally {
183
+ ScriptableObject.deleteProperty(scope, hostOpName);
184
+ }
185
+ } catch (EvaluatorException e) {
186
+ return errorFromRhino(id, "compile_error", e);
187
+ } catch (RhinoException e) {
188
+ return errorFromRhino(id, "runtime_error", e);
189
+ } catch (Error e) {
190
+ if (isInterrupt(e)) {
191
+ return timeoutResponse(id);
192
+ }
193
+ throw e;
194
+ }
195
+ }
196
+
197
+ final Script script;
198
+ try {
199
+ script = cx.compileString(source, sourceName, 1, null);
200
+ } catch (EvaluatorException e) {
201
+ return errorFromRhino(id, "compile_error", e);
202
+ } catch (RhinoException e) {
203
+ return errorFromRhino(id, "compile_error", e);
204
+ }
205
+
206
+ final Object completion;
207
+ try {
208
+ completion = script.exec(cx, scope);
209
+ } catch (RhinoException e) {
210
+ return errorFromRhino(id, "runtime_error", e);
211
+ } catch (Error e) {
212
+ if (isInterrupt(e)) {
213
+ return timeoutResponse(id);
214
+ }
215
+ throw e;
216
+ }
217
+ final String resultGlobal = Json.optionalString(job, "resultGlobal");
218
+ final Object result = resultGlobal == null
219
+ ? completion
220
+ : ScriptableObject.getProperty(scope, resultGlobal);
221
+ return response(id, "ok", JsValues.of(result), null);
222
+ } finally {
223
+ Context.exit();
224
+ }
225
+ }
226
+
227
+ static void injectGlobals(SimpleScriptContext scriptContext, Object globalsRaw) {
228
+ if (globalsRaw == null) {
229
+ return;
230
+ }
231
+ Map<String, Object> globals = Json.asObject(globalsRaw, "globals");
232
+ for (Map.Entry<String, Object> e : globals.entrySet()) {
233
+ scriptContext.setAttribute(e.getKey(), e.getValue(), ScriptContext.ENGINE_SCOPE);
234
+ }
235
+ }
236
+
237
+ static boolean isInterrupt(Error e) {
238
+ return "Interrupt.".equals(e.getMessage());
239
+ }
240
+
241
+ static Map<String, Object> errorFromRhino(String id, String outcome, RhinoException e) {
242
+ return errorResponse(
243
+ id, outcome, e, e.sourceName(), e.lineNumber(), e.columnNumber(), e.lineSource());
244
+ }
245
+
246
+ static Map<String, Object> timeoutResponse(String id) {
247
+ Map<String, Object> err = new LinkedHashMap<String, Object>();
248
+ err.put("class", "java.lang.Error");
249
+ err.put("message", "Interrupt.");
250
+ err.put("sourceName", null);
251
+ err.put("line", Integer.valueOf(-1));
252
+ err.put("column", Integer.valueOf(-1));
253
+ err.put("lineSource", null);
254
+ return response(id, "timeout", JsValues.of(Scriptable.NOT_FOUND), err);
255
+ }
256
+
257
+ static Map<String, Object> errorResponse(
258
+ String id,
259
+ String outcome,
260
+ Throwable t,
261
+ String sourceName,
262
+ int line,
263
+ int column,
264
+ String lineSource) {
265
+ Map<String, Object> err = new LinkedHashMap<String, Object>();
266
+ err.put("class", t.getClass().getName());
267
+ err.put("message", t.getMessage());
268
+ err.put("sourceName", sourceName);
269
+ err.put("line", Integer.valueOf(line));
270
+ err.put("column", Integer.valueOf(column));
271
+ err.put("lineSource", lineSource);
272
+ return response(id, outcome, JsValues.of(Scriptable.NOT_FOUND), err);
273
+ }
274
+
275
+ static Map<String, Object> response(
276
+ String id, String outcome, JsValues value, Map<String, Object> error) {
277
+ Map<String, Object> rec = new LinkedHashMap<String, Object>();
278
+ rec.put("id", id);
279
+ rec.put("outcome", outcome);
280
+ rec.put("valueKind", value.kind);
281
+ rec.put("value", value.json);
282
+ rec.put("error", error);
283
+ return rec;
284
+ }
285
+
286
+ static void write(Map<String, Object> rec) {
287
+ OUT.println(Json.stringify(rec));
288
+ }
289
+ }
@@ -0,0 +1,147 @@
1
+ import java.util.ArrayList;
2
+ import java.util.List;
3
+ import javax.script.Bindings;
4
+ import javax.script.ScriptContext;
5
+ import org.mozilla.javascript.Context;
6
+ import org.mozilla.javascript.NativeObject;
7
+ import org.mozilla.javascript.Scriptable;
8
+ import org.mozilla.javascript.Wrapper;
9
+
10
+ /**
11
+ * Replica of AM 8.1.1 {@code
12
+ * org.forgerock.openam.scripting.factories.ScriptContextScope}, measured with
13
+ * {@code javap -p -c} on {@code openam-scripting-8.1.1.jar}.
14
+ *
15
+ * <p>Implements {@link Scriptable} only — not {@code ScriptableObject} and not
16
+ * {@code ConstProperties}. That is the lever for top-level {@code const}:
17
+ * Rhino's {@code putConstProperty} silently drops the initializer when the
18
+ * scope is not {@code ConstProperties}, after {@code defineConstProperty} has
19
+ * already {@code put} {@code Undefined}. Decision-node scripts therefore read
20
+ * top-level {@code const} back as {@code undefined}.
21
+ *
22
+ * <p>AM's class depends on {@code org.forgerock.util.Reject}; this replica does
23
+ * not, so we do not have to extract forgerock-util.
24
+ */
25
+ final class ScriptContextScope implements Scriptable {
26
+
27
+ private final ScriptContext scriptContext;
28
+ private Scriptable prototype;
29
+ private Scriptable parentScope;
30
+
31
+ ScriptContextScope(ScriptContext scriptContext) {
32
+ if (scriptContext == null) {
33
+ throw new IllegalArgumentException("scriptContext");
34
+ }
35
+ this.scriptContext = scriptContext;
36
+ }
37
+
38
+ @Override
39
+ public String getClassName() {
40
+ return "ScriptContextScope";
41
+ }
42
+
43
+ @Override
44
+ public boolean has(String name, Scriptable start) {
45
+ return scriptContext.getAttributesScope(name) != -1;
46
+ }
47
+
48
+ @Override
49
+ public boolean has(int index, Scriptable start) {
50
+ return false;
51
+ }
52
+
53
+ @Override
54
+ public Object get(String name, Scriptable start) {
55
+ int scope = scriptContext.getAttributesScope(name);
56
+ if (scope != -1) {
57
+ Object value = scriptContext.getAttribute(name, scope);
58
+ return Context.javaToJS(value, this);
59
+ }
60
+ return Scriptable.NOT_FOUND;
61
+ }
62
+
63
+ @Override
64
+ public Object get(int index, Scriptable start) {
65
+ return Scriptable.NOT_FOUND;
66
+ }
67
+
68
+ @Override
69
+ public void put(String name, Scriptable start, Object value) {
70
+ int scope = scriptContext.getAttributesScope(name);
71
+ if (scope == -1) {
72
+ scope = ScriptContext.ENGINE_SCOPE;
73
+ }
74
+ if (value instanceof Wrapper) {
75
+ value = ((Wrapper) value).unwrap();
76
+ }
77
+ scriptContext.setAttribute(name, value, scope);
78
+ }
79
+
80
+ @Override
81
+ public void put(int index, Scriptable start, Object value) {
82
+ // AM no-ops integer keys.
83
+ }
84
+
85
+ @Override
86
+ public void delete(String name) {
87
+ int scope = scriptContext.getAttributesScope(name);
88
+ if (scope != -1) {
89
+ scriptContext.removeAttribute(name, scope);
90
+ }
91
+ }
92
+
93
+ @Override
94
+ public void delete(int index) {
95
+ // AM no-ops integer keys.
96
+ }
97
+
98
+ @Override
99
+ public Scriptable getPrototype() {
100
+ return prototype;
101
+ }
102
+
103
+ @Override
104
+ public void setPrototype(Scriptable prototype) {
105
+ this.prototype = prototype;
106
+ }
107
+
108
+ @Override
109
+ public Scriptable getParentScope() {
110
+ return parentScope;
111
+ }
112
+
113
+ @Override
114
+ public void setParentScope(Scriptable parentScope) {
115
+ this.parentScope = parentScope;
116
+ }
117
+
118
+ @Override
119
+ public Object[] getIds() {
120
+ List<Object> ids = new ArrayList<Object>();
121
+ for (Integer scope : scriptContext.getScopes()) {
122
+ Bindings bindings = scriptContext.getBindings(scope.intValue());
123
+ // AM does not null-check; SimpleScriptContext's GLOBAL_SCOPE starts null.
124
+ if (bindings != null) {
125
+ ids.addAll(bindings.keySet());
126
+ }
127
+ }
128
+ return ids.toArray();
129
+ }
130
+
131
+ @Override
132
+ public Object getDefaultValue(Class<?> hint) {
133
+ return NativeObject.getDefaultValue(this, hint);
134
+ }
135
+
136
+ @Override
137
+ public boolean hasInstance(Scriptable instance) {
138
+ Scriptable proto = instance.getPrototype();
139
+ while (proto != null) {
140
+ if (proto.equals(this)) {
141
+ return true;
142
+ }
143
+ proto = proto.getPrototype();
144
+ }
145
+ return false;
146
+ }
147
+ }
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "@agiledigital/pingone-aic-script-tester",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Local Rhino harness: mock-surface generator and typed client for the long-lived JVM runner.",
6
+ "license": "MIT OR Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/agiledigital-labs/pingone-aic-manager.git",
10
+ "directory": "packages/rhino-local"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/src/harness/index.d.ts",
18
+ "default": "./dist/src/harness/index.js"
19
+ },
20
+ "./case": {
21
+ "types": "./dist/src/case/index.d.ts",
22
+ "default": "./dist/src/case/index.js"
23
+ },
24
+ "./aic": {
25
+ "types": "./dist/src/aic/index.d.ts",
26
+ "default": "./dist/src/aic/index.js"
27
+ },
28
+ "./bindings": {
29
+ "types": "./dist/src/bindings/index.d.ts",
30
+ "default": "./dist/src/bindings/index.js"
31
+ },
32
+ "./runner": {
33
+ "types": "./dist/src/runner.d.ts",
34
+ "default": "./dist/src/runner.js"
35
+ },
36
+ "./profile": {
37
+ "types": "./dist/src/profile/index.d.ts",
38
+ "default": "./dist/src/profile/index.js"
39
+ },
40
+ "./diagnostics": {
41
+ "types": "./dist/src/diagnostics.d.ts",
42
+ "default": "./dist/src/diagnostics.js"
43
+ },
44
+ "./package.json": "./package.json"
45
+ },
46
+ "bin": {
47
+ "aic-script-tester-show-log": "dist/bin/show-log.js",
48
+ "aic-script-tester-pull-profile": "dist/bin/pull-profile.js",
49
+ "aic-script-tester-fetch-jar": "dist/bin/fetch-jar.js"
50
+ },
51
+ "files": [
52
+ "dist/",
53
+ "generated/",
54
+ "java/*.java",
55
+ "LICENSE-APACHE",
56
+ "LICENSE-MIT",
57
+ "src/bindings/rhino/runtime.cjs"
58
+ ],
59
+ "engines": {
60
+ "node": ">=24"
61
+ },
62
+ "scripts": {
63
+ "generate": "node src/generate.ts",
64
+ "measure": "node src/measure.ts",
65
+ "test": "vitest run",
66
+ "typecheck": "tsc --noEmit",
67
+ "lint": "eslint . --max-warnings 0",
68
+ "lint:am": "eslint --config eslint.am.config.js generated src/bindings cases --max-warnings 0",
69
+ "pull-profile": "node bin/pull-profile.ts",
70
+ "show-log": "node bin/show-log.ts",
71
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && node src/build-classes.ts",
72
+ "prepack": "npm run build",
73
+ "fetch-jar": "node bin/fetch-jar.ts"
74
+ },
75
+ "devDependencies": {
76
+ "@eslint/js": "10.0.1",
77
+ "@types/node": "24.19.0",
78
+ "eslint": "10.11.0",
79
+ "typescript": "5.9.3",
80
+ "typescript-eslint": "8.71.0",
81
+ "vitest": "5.0.2",
82
+ "zod": "^4.6.4"
83
+ },
84
+ "peerDependencies": {
85
+ "vitest": "^5.0.2",
86
+ "zod": "^4.6.4"
87
+ }
88
+ }