deepline 0.3.97 → 0.3.98

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 (36) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +144 -4
  2. package/dist/bundling-sources/sdk/src/index.ts +17 -4
  3. package/dist/bundling-sources/sdk/src/monitor-fleets.ts +1 -0
  4. package/dist/bundling-sources/sdk/src/monitor-input-contract.ts +1 -0
  5. package/dist/bundling-sources/sdk/src/monitors.ts +8 -25
  6. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  7. package/dist/bundling-sources/shared_libs/integration-contracts/index.ts +1 -0
  8. package/dist/bundling-sources/shared_libs/integration-contracts/monitor-fleet-contract.ts +218 -16
  9. package/dist/bundling-sources/shared_libs/integration-contracts/monitor-input-contract.ts +455 -0
  10. package/dist/bundling-sources/shared_libs/monitors/fleets/plan.ts +6 -1
  11. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +2 -1
  12. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +12 -0
  13. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +1 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +19 -3
  15. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +5 -1
  16. package/dist/cli/index.js +1004 -289
  17. package/dist/cli/index.mjs +1004 -289
  18. package/dist/index.d.mts +43 -24
  19. package/dist/index.d.ts +43 -24
  20. package/dist/index.js +604 -41
  21. package/dist/index.mjs +600 -41
  22. package/dist/install-integrity.json +6 -0
  23. package/dist/monitor-fleet-contract.d.mts +44 -8
  24. package/dist/monitor-fleet-contract.d.ts +44 -8
  25. package/dist/monitor-fleet-contract.js +354 -27
  26. package/dist/monitor-fleet-contract.mjs +343 -27
  27. package/dist/monitor-input-contract.d.mts +33 -0
  28. package/dist/monitor-input-contract.d.ts +33 -0
  29. package/dist/monitor-input-contract.js +392 -0
  30. package/dist/monitor-input-contract.mjs +353 -0
  31. package/dist/plays/bundle-play-file.mjs +1 -1
  32. package/dist/release.d.mts +1 -1
  33. package/dist/release.d.ts +1 -1
  34. package/dist/release.js +1 -1
  35. package/dist/release.mjs +1 -1
  36. package/package.json +7 -1
@@ -0,0 +1,455 @@
1
+ import Handlebars from 'handlebars';
2
+
3
+ export type MonitorInputIssue = {
4
+ severity: 'error' | 'warning' | 'info';
5
+ code: string;
6
+ path: string;
7
+ message: string;
8
+ suggestion?: string;
9
+ };
10
+
11
+ export type MonitorSpec = {
12
+ key: string;
13
+ tool: string;
14
+ name?: string;
15
+ payload: Record<string, unknown>;
16
+ };
17
+
18
+ export type BatchMonitorInput = {
19
+ version: 1;
20
+ kind: 'batch';
21
+ monitors: MonitorSpec[];
22
+ };
23
+
24
+ type UnknownRecord = Record<string, unknown>;
25
+
26
+ function authoredMonitorFieldPath(path: string, field: string): string {
27
+ // Batch JSON is an array-shaped document, so use an array path in the two
28
+ // prescriptive migration errors. Fleet retains its natural `monitor.field`
29
+ // path while both commands point at the exact authored field.
30
+ const batch = /^monitors\.(\d+)$/.exec(path);
31
+ return `${batch ? `monitors[${batch[1]}]` : path}.${field}`;
32
+ }
33
+
34
+ function record(value: unknown): UnknownRecord | null {
35
+ return value && typeof value === 'object' && !Array.isArray(value)
36
+ ? (value as UnknownRecord)
37
+ : null;
38
+ }
39
+
40
+ function json(value: unknown, path: string, issues: MonitorInputIssue[]): void {
41
+ if (
42
+ value === null ||
43
+ typeof value === 'string' ||
44
+ typeof value === 'boolean' ||
45
+ (typeof value === 'number' && Number.isFinite(value))
46
+ ) {
47
+ return;
48
+ }
49
+ if (Array.isArray(value)) {
50
+ value.forEach((child, index) => json(child, `${path}.${index}`, issues));
51
+ return;
52
+ }
53
+ const object = record(value);
54
+ if (!object) {
55
+ issues.push({
56
+ severity: 'error',
57
+ code: 'invalid_monitor_json_value',
58
+ path,
59
+ message: 'Monitor values must be JSON values.',
60
+ });
61
+ return;
62
+ }
63
+ for (const [key, child] of Object.entries(object)) {
64
+ json(child, `${path}.${key}`, issues);
65
+ }
66
+ }
67
+
68
+ function monitorSpec(
69
+ value: unknown,
70
+ path: string,
71
+ issues: MonitorInputIssue[],
72
+ ) {
73
+ const input = record(value);
74
+ if (!input) {
75
+ issues.push({
76
+ severity: 'error',
77
+ code: 'invalid_monitor_spec',
78
+ path,
79
+ message: 'A monitor must be a JSON object.',
80
+ });
81
+ return null;
82
+ }
83
+ const allowed = new Set(['key', 'tool', 'name', 'payload']);
84
+ for (const key of Object.keys(input)) {
85
+ if (!allowed.has(key)) {
86
+ if (key === 'controls') {
87
+ issues.push({
88
+ severity: 'error',
89
+ code: 'CONTROLS_NOT_SUPPORTED',
90
+ path: authoredMonitorFieldPath(path, 'controls'),
91
+ message:
92
+ 'Operational controls are managed by Deepline and cannot be authored in Batch or Fleet JSON.',
93
+ suggestion:
94
+ 'Remove controls. Bind downstream automation in a Play with sqlListeners.',
95
+ });
96
+ continue;
97
+ }
98
+ if (key === 'play') {
99
+ issues.push({
100
+ severity: 'error',
101
+ code: 'PLAY_BINDING_NOT_IN_MONITOR_SPEC',
102
+ path: authoredMonitorFieldPath(path, 'play'),
103
+ message: 'A monitor does not own Play bindings.',
104
+ suggestion:
105
+ 'Declare sqlListeners in the Play, or run: deepline plays bootstrap monitor-triggered --out on-event.play.ts',
106
+ });
107
+ continue;
108
+ }
109
+ issues.push({
110
+ severity: 'error',
111
+ code: 'unknown_monitor_field',
112
+ path: `${path}.${key}`,
113
+ message: `Monitor definitions do not accept '${key}'.`,
114
+ });
115
+ }
116
+ }
117
+ const key = typeof input.key === 'string' ? input.key.trim() : '';
118
+ const tool = typeof input.tool === 'string' ? input.tool.trim() : '';
119
+ const name =
120
+ input.name === undefined
121
+ ? undefined
122
+ : typeof input.name === 'string' && input.name.trim()
123
+ ? input.name.trim()
124
+ : null;
125
+ const payload = record(input.payload);
126
+ if (!key) {
127
+ issues.push({
128
+ severity: 'error',
129
+ code: 'invalid_monitor_key',
130
+ path: `${path}.key`,
131
+ message: 'Monitor key must be a non-empty string.',
132
+ });
133
+ }
134
+ if (!tool) {
135
+ issues.push({
136
+ severity: 'error',
137
+ code: 'invalid_monitor_tool',
138
+ path: `${path}.tool`,
139
+ message: 'Monitor tool must be a non-empty literal string.',
140
+ });
141
+ }
142
+ if (name === null) {
143
+ issues.push({
144
+ severity: 'error',
145
+ code: 'invalid_monitor_name',
146
+ path: `${path}.name`,
147
+ message: 'Monitor name must be a non-empty string when supplied.',
148
+ });
149
+ }
150
+ if (!payload) {
151
+ issues.push({
152
+ severity: 'error',
153
+ code: 'invalid_monitor_payload',
154
+ path: `${path}.payload`,
155
+ message: 'Monitor payload must be an object.',
156
+ });
157
+ } else {
158
+ json(payload, `${path}.payload`, issues);
159
+ }
160
+ if (!key || !tool || !payload || name === null) {
161
+ return null;
162
+ }
163
+ return {
164
+ key,
165
+ tool,
166
+ ...(name ? { name } : {}),
167
+ payload,
168
+ } satisfies MonitorSpec;
169
+ }
170
+
171
+ function issueOrder(left: MonitorInputIssue, right: MonitorInputIssue) {
172
+ return (
173
+ left.path.localeCompare(right.path) ||
174
+ left.severity.localeCompare(right.severity) ||
175
+ left.code.localeCompare(right.code)
176
+ );
177
+ }
178
+
179
+ export function lintMonitorBatchInput(value: unknown): {
180
+ normalized?: BatchMonitorInput;
181
+ issues: MonitorInputIssue[];
182
+ } {
183
+ const issues: MonitorInputIssue[] = [];
184
+ // Versionless `{ monitors: [...] }` was the original REST/SDK envelope.
185
+ // Continue to admit it so installed SDKs remain compatible, but normalize it
186
+ // before anything is persisted or sent to the provider.
187
+ const versionlessEnvelope =
188
+ !Array.isArray(value) &&
189
+ (() => {
190
+ const candidate = record(value);
191
+ return (
192
+ candidate !== null &&
193
+ Object.keys(candidate).length === 1 &&
194
+ Object.prototype.hasOwnProperty.call(candidate, 'monitors')
195
+ );
196
+ })();
197
+ const legacy = Array.isArray(value) || versionlessEnvelope;
198
+ const input = legacy ? null : record(value);
199
+ let monitors: unknown[] | null = Array.isArray(value)
200
+ ? value
201
+ : versionlessEnvelope
202
+ ? (() => {
203
+ const candidate = record(value)?.monitors;
204
+ return Array.isArray(candidate) ? candidate : null;
205
+ })()
206
+ : null;
207
+ if (Array.isArray(value)) {
208
+ issues.push({
209
+ severity: 'warning',
210
+ code: 'deprecated_batch_array',
211
+ path: '',
212
+ message: 'Bare monitor arrays are supported for compatibility.',
213
+ suggestion:
214
+ 'Wrap the list in {"version":1,"kind":"batch","monitors":[...]}.',
215
+ });
216
+ } else if (versionlessEnvelope) {
217
+ issues.push({
218
+ severity: 'warning',
219
+ code: 'deprecated_batch_missing_envelope_fields',
220
+ path: '',
221
+ message: 'Versionless monitor envelopes are supported for compatibility.',
222
+ suggestion: 'Add "version": 1 and "kind": "batch".',
223
+ });
224
+ if (!monitors) {
225
+ issues.push({
226
+ severity: 'error',
227
+ code: 'invalid_batch_monitors',
228
+ path: 'monitors',
229
+ message: 'Batch monitors must be an array.',
230
+ });
231
+ }
232
+ } else if (!input) {
233
+ issues.push({
234
+ severity: 'error',
235
+ code: 'invalid_batch',
236
+ path: '',
237
+ message: 'Batch input must be an object or a legacy array.',
238
+ });
239
+ } else {
240
+ for (const key of Object.keys(input)) {
241
+ if (!['version', 'kind', 'monitors'].includes(key)) {
242
+ issues.push({
243
+ severity: 'error',
244
+ code:
245
+ key === 'source' || key === 'monitor'
246
+ ? 'batch_fleet_shape_mixup'
247
+ : 'unknown_batch_field',
248
+ path: key,
249
+ message: `Batch input does not accept '${key}'.`,
250
+ });
251
+ }
252
+ }
253
+ if (input.version !== 1) {
254
+ issues.push({
255
+ severity: 'error',
256
+ code: 'unsupported_batch_version',
257
+ path: 'version',
258
+ message: 'Batch input version must be 1.',
259
+ });
260
+ }
261
+ if (input.kind !== 'batch') {
262
+ issues.push({
263
+ severity: 'error',
264
+ code: 'invalid_batch_kind',
265
+ path: 'kind',
266
+ message: 'Batch input kind must be "batch".',
267
+ });
268
+ }
269
+ monitors = Array.isArray(input.monitors) ? input.monitors : null;
270
+ if (!monitors) {
271
+ issues.push({
272
+ severity: 'error',
273
+ code: 'invalid_batch_monitors',
274
+ path: 'monitors',
275
+ message: 'Batch monitors must be an array.',
276
+ });
277
+ }
278
+ }
279
+ if (!monitors || monitors.length === 0) {
280
+ if (monitors?.length === 0) {
281
+ issues.push({
282
+ severity: 'error',
283
+ code: 'empty_batch',
284
+ path: 'monitors',
285
+ message: 'A Batch needs at least one monitor.',
286
+ });
287
+ }
288
+ return { issues: issues.sort(issueOrder) };
289
+ }
290
+ const normalized = monitors.map((item, index) =>
291
+ monitorSpec(item, `monitors.${index}`, issues),
292
+ );
293
+ const seen = new Map<string, number>();
294
+ normalized.forEach((item, index) => {
295
+ if (!item) return;
296
+ const first = seen.get(item.key);
297
+ if (first !== undefined) {
298
+ for (const position of [first, index]) {
299
+ issues.push({
300
+ severity: 'error',
301
+ code: 'duplicate_monitor_key',
302
+ path: `monitors.${position}.key`,
303
+ message: `Duplicate monitor key '${item.key}'.`,
304
+ });
305
+ }
306
+ } else {
307
+ seen.set(item.key, index);
308
+ }
309
+ });
310
+ const ordered = issues.sort(issueOrder);
311
+ return ordered.some((issue) => issue.severity === 'error')
312
+ ? { issues: ordered }
313
+ : {
314
+ normalized: {
315
+ version: 1,
316
+ kind: 'batch',
317
+ monitors: normalized as MonitorSpec[],
318
+ },
319
+ issues: ordered,
320
+ };
321
+ }
322
+
323
+ function validateHandlebars(
324
+ value: string,
325
+ path: string,
326
+ issues: MonitorInputIssue[],
327
+ ) {
328
+ if (!value.includes('{{')) return;
329
+ try {
330
+ Handlebars.parse(value);
331
+ } catch (error) {
332
+ issues.push({
333
+ severity: 'error',
334
+ code: 'invalid_handlebars_template',
335
+ path,
336
+ message:
337
+ error instanceof Error ? error.message : 'Invalid Handlebars template.',
338
+ });
339
+ return;
340
+ }
341
+ const expressions = value.match(/{{[\s\S]*?}}/g) ?? [];
342
+ if (
343
+ expressions.some(
344
+ (expression) => !/^{{\s*[A-Za-z_][A-Za-z0-9_]*\s*}}$/.test(expression),
345
+ )
346
+ ) {
347
+ issues.push({
348
+ severity: 'error',
349
+ code: 'unsupported_handlebars_expression',
350
+ path,
351
+ message:
352
+ 'Fleet templates allow only direct source-row fields such as {{domain}}; helpers, blocks, partials, paths, and prototype access are disabled.',
353
+ });
354
+ }
355
+ }
356
+
357
+ function walkTemplates(
358
+ value: unknown,
359
+ path: string,
360
+ issues: MonitorInputIssue[],
361
+ ): void {
362
+ if (typeof value === 'string') return validateHandlebars(value, path, issues);
363
+ if (Array.isArray(value)) {
364
+ value.forEach((item, index) =>
365
+ walkTemplates(item, `${path}.${index}`, issues),
366
+ );
367
+ return;
368
+ }
369
+ const input = record(value);
370
+ if (!input) return;
371
+ for (const [key, child] of Object.entries(input)) {
372
+ walkTemplates(child, `${path}.${key}`, issues);
373
+ }
374
+ }
375
+
376
+ export function lintMonitorSpecTemplate(
377
+ value: unknown,
378
+ path = 'monitor',
379
+ ): { normalized?: MonitorSpec; issues: MonitorInputIssue[] } {
380
+ const issues: MonitorInputIssue[] = [];
381
+ const normalized = monitorSpec(value, path, issues);
382
+ const input = record(value);
383
+ if (input && typeof input.tool === 'string' && input.tool.includes('{{')) {
384
+ issues.push({
385
+ severity: 'error',
386
+ code: 'templated_monitor_tool',
387
+ path: `${path}.tool`,
388
+ message:
389
+ 'Fleet monitor tool must be literal; only key, name, and payload may be templated.',
390
+ });
391
+ }
392
+ if (input) {
393
+ for (const field of ['key', 'name', 'payload']) {
394
+ if (input[field] !== undefined)
395
+ walkTemplates(input[field], `${path}.${field}`, issues);
396
+ }
397
+ }
398
+ const ordered = issues.sort(issueOrder);
399
+ return ordered.some((issue) => issue.severity === 'error')
400
+ ? { issues: ordered }
401
+ : { normalized: normalized!, issues: ordered };
402
+ }
403
+
404
+ function renderValue(value: unknown, row: Record<string, unknown>): unknown {
405
+ if (typeof value === 'string' && value.includes('{{')) {
406
+ const context = Object.assign(Object.create(null), row);
407
+ return Handlebars.compile(value, {
408
+ noEscape: true,
409
+ strict: true,
410
+ knownHelpersOnly: true,
411
+ preventIndent: true,
412
+ })(context, {
413
+ allowProtoMethodsByDefault: false,
414
+ allowProtoPropertiesByDefault: false,
415
+ helpers: Object.create(null),
416
+ partials: Object.create(null),
417
+ });
418
+ }
419
+ if (Array.isArray(value)) return value.map((item) => renderValue(item, row));
420
+ const input = record(value);
421
+ if (!input) return value;
422
+ return Object.fromEntries(
423
+ Object.entries(input).map(([key, item]) => [key, renderValue(item, row)]),
424
+ );
425
+ }
426
+
427
+ export function renderMonitorSpecTemplate(
428
+ template: MonitorSpec,
429
+ row: Record<string, unknown>,
430
+ ): { spec?: MonitorSpec; issues: MonitorInputIssue[] } {
431
+ const lint = lintMonitorSpecTemplate(template);
432
+ if (!lint.normalized) return { issues: lint.issues };
433
+ try {
434
+ const rendered = renderValue(lint.normalized, row);
435
+ const issues: MonitorInputIssue[] = [];
436
+ const spec = monitorSpec(rendered, 'monitor', issues);
437
+ return spec
438
+ ? { spec, issues: issues.sort(issueOrder) }
439
+ : { issues: issues.sort(issueOrder) };
440
+ } catch (error) {
441
+ return {
442
+ issues: [
443
+ {
444
+ severity: 'error',
445
+ code: 'monitor_template_render_failed',
446
+ path: 'monitor',
447
+ message:
448
+ error instanceof Error
449
+ ? error.message
450
+ : 'Fleet template rendering failed.',
451
+ },
452
+ ],
453
+ };
454
+ }
455
+ }
@@ -47,7 +47,12 @@ export type OwnedFleetMonitor = {
47
47
  | 'rate_limited'
48
48
  | 'settled'
49
49
  | 'blocked'
50
- | 'failed';
50
+ | 'failed'
51
+ /**
52
+ * A policy-suspended member remains owned so the Fleet can explicitly
53
+ * reactivate it, but it has no active convergence work until then.
54
+ */
55
+ | null;
51
56
  desiredHash: string | null;
52
57
  appliedHash: string | null;
53
58
  firstMissingAt: number | null;
@@ -86,7 +86,8 @@ export type ProviderMonitorBatchOperationState =
86
86
  | 'running'
87
87
  | 'retry_scheduled'
88
88
  | 'completed'
89
- | 'failed';
89
+ | 'failed'
90
+ | 'cancelled';
90
91
 
91
92
  const IDEMPOTENCY_KEY = /^[A-Za-z0-9][A-Za-z0-9._-]{0,95}$/;
92
93
 
@@ -698,5 +698,17 @@
698
698
  "owner": "billing",
699
699
  "criticality": "critical",
700
700
  "failureAlert": "convex_action_wrapper"
701
+ },
702
+ {
703
+ "id": "convex.monitor-deployment-job-tick",
704
+ "name": "Monitor deployment job tick",
705
+ "scheduler": "convex_cron",
706
+ "cadence": "every 60s",
707
+ "timezone": "UTC",
708
+ "source": "packages/convex/crons.ts",
709
+ "locator": "monitor deployment job tick",
710
+ "owner": "monitors",
711
+ "criticality": "critical",
712
+ "failureAlert": "convex_action_wrapper"
701
713
  }
702
714
  ]
@@ -15,6 +15,7 @@ export const MANUALLY_RUNNABLE_CONVEX_CRON_JOB_IDS = [
15
15
  'convex.cleanup-expired-domain-health-cache',
16
16
  'convex.salesforce-oauth-refresh-maintenance',
17
17
  'convex.monitor-fleet-convergence-tick',
18
+ 'convex.monitor-deployment-job-tick',
18
19
  'convex.provider-monitor-global-audit-daily',
19
20
  'convex.recover-notification-delivery-work',
20
21
  'convex.cleanup-expired-notification-audit-records',
@@ -167,7 +167,9 @@ export type MonitorFleetDispatchTokenClaims = {
167
167
  org_id: string;
168
168
  purpose: typeof MONITOR_FLEET_DISPATCH_PURPOSE;
169
169
  fleet_id?: string;
170
- operation: 'dispatch' | 'daily_sync';
170
+ /** Monitor Job dispatches share this bounded credential wrapper. */
171
+ job_id?: string;
172
+ operation: 'dispatch' | 'daily_sync' | 'job_dispatch';
171
173
  sub: 'monitor_fleet_dispatcher';
172
174
  v: typeof INTERNAL_BOOTSTRAP_TOKEN_VERSION;
173
175
  };
@@ -1116,10 +1118,17 @@ export async function verifyProductNotificationUnsubscribeToken(
1116
1118
 
1117
1119
  export async function mintMonitorFleetDispatchToken(input: {
1118
1120
  orgId: string;
1119
- operation: 'dispatch' | 'daily_sync';
1121
+ operation: 'dispatch' | 'daily_sync' | 'job_dispatch';
1120
1122
  fleetId?: string;
1123
+ jobId?: string;
1121
1124
  nowMs?: number;
1122
1125
  }): Promise<string> {
1126
+ if (input.operation === 'job_dispatch' && !input.jobId?.trim()) {
1127
+ throw new Error('Monitor Job dispatch tokens require a job id.');
1128
+ }
1129
+ if (input.operation !== 'job_dispatch' && input.jobId !== undefined) {
1130
+ throw new Error('Only Monitor Job dispatch tokens may carry a job id.');
1131
+ }
1123
1132
  const issuedAt = Math.floor((input.nowMs ?? Date.now()) / 1000);
1124
1133
  const claims: MonitorFleetDispatchTokenClaims = {
1125
1134
  v: INTERNAL_BOOTSTRAP_TOKEN_VERSION,
@@ -1129,6 +1138,7 @@ export async function mintMonitorFleetDispatchToken(input: {
1129
1138
  org_id: input.orgId,
1130
1139
  operation: input.operation,
1131
1140
  ...(input.fleetId ? { fleet_id: input.fleetId } : {}),
1141
+ ...(input.jobId ? { job_id: input.jobId } : {}),
1132
1142
  sub: 'monitor_fleet_dispatcher',
1133
1143
  iat: issuedAt,
1134
1144
  exp: issuedAt + INTERNAL_BOOTSTRAP_TOKEN_TTL_SECONDS,
@@ -1168,8 +1178,14 @@ export async function verifyMonitorFleetDispatchToken(
1168
1178
  claims.sub !== 'monitor_fleet_dispatcher' ||
1169
1179
  typeof claims.org_id !== 'string' ||
1170
1180
  !claims.org_id ||
1171
- !['dispatch', 'daily_sync'].includes(String(claims.operation)) ||
1181
+ !['dispatch', 'daily_sync', 'job_dispatch'].includes(
1182
+ String(claims.operation),
1183
+ ) ||
1172
1184
  (claims.fleet_id !== undefined && typeof claims.fleet_id !== 'string') ||
1185
+ (claims.job_id !== undefined && typeof claims.job_id !== 'string') ||
1186
+ (claims.operation === 'job_dispatch' &&
1187
+ (typeof claims.job_id !== 'string' || !claims.job_id)) ||
1188
+ (claims.operation !== 'job_dispatch' && claims.job_id !== undefined) ||
1173
1189
  typeof claims.iat !== 'number' ||
1174
1190
  !Number.isFinite(claims.iat) ||
1175
1191
  typeof claims.exp !== 'number' ||
@@ -1827,7 +1827,11 @@ function importedPlayProxyPlugin(
1827
1827
  name: 'deepline-imported-play-proxy',
1828
1828
  setup(buildContext) {
1829
1829
  buildContext.onResolve({ filter: /.*/ }, async (args) => {
1830
- if (!args.importer || !isLocalSpecifier(args.path)) {
1830
+ if (
1831
+ !args.importer ||
1832
+ !isLocalSpecifier(args.path) ||
1833
+ args.importer.split(/[\\/]+/).includes('node_modules')
1834
+ ) {
1831
1835
  return null;
1832
1836
  }
1833
1837