@spotpatch/dev-server 0.7.0 → 0.8.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.
package/dist/index.d.cts CHANGED
@@ -155,6 +155,7 @@ declare const DEFAULT_OPTIONS: Readonly<{
155
155
  readonly graphMaxCallsites: 100;
156
156
  readonly analysisTimeoutMs: 2000;
157
157
  readonly reportMaxFields: 100;
158
+ readonly sourceMaxComponents: 256;
158
159
  }>;
159
160
  }>;
160
161
  externalAgent: Readonly<{
@@ -216,7 +217,7 @@ type SourceIdFactory = () => string;
216
217
 
217
218
  interface SourceRegistry {
218
219
  register(absolutePath: string): string;
219
- registerDataFlowComponents(absolutePath: string, sourceVersion: string, components: readonly DataFlowComponentAnchorInput[]): void;
220
+ registerDataFlowComponents(absolutePath: string, sourceVersion: string, components: readonly DataFlowComponentAnchorInput[]): string;
220
221
  resolve(fileId: string): string | undefined;
221
222
  resolveDataFlowComponent(componentSourceId: string): DataFlowComponentAnchor | undefined;
222
223
  clear(): void;
package/dist/index.d.ts CHANGED
@@ -155,6 +155,7 @@ declare const DEFAULT_OPTIONS: Readonly<{
155
155
  readonly graphMaxCallsites: 100;
156
156
  readonly analysisTimeoutMs: 2000;
157
157
  readonly reportMaxFields: 100;
158
+ readonly sourceMaxComponents: 256;
158
159
  }>;
159
160
  }>;
160
161
  externalAgent: Readonly<{
@@ -216,7 +217,7 @@ type SourceIdFactory = () => string;
216
217
 
217
218
  interface SourceRegistry {
218
219
  register(absolutePath: string): string;
219
- registerDataFlowComponents(absolutePath: string, sourceVersion: string, components: readonly DataFlowComponentAnchorInput[]): void;
220
+ registerDataFlowComponents(absolutePath: string, sourceVersion: string, components: readonly DataFlowComponentAnchorInput[]): string;
220
221
  resolve(fileId: string): string | undefined;
221
222
  resolveDataFlowComponent(componentSourceId: string): DataFlowComponentAnchor | undefined;
222
223
  clear(): void;
package/dist/index.js CHANGED
@@ -2478,6 +2478,7 @@ function createSourceRegistry(options = {}) {
2478
2478
  );
2479
2479
  }
2480
2480
  componentIdsByPath.set(normalizedPath, currentIds);
2481
+ return fileId;
2481
2482
  },
2482
2483
  resolve(fileId) {
2483
2484
  return idToPath.get(fileId);
@@ -4161,17 +4162,33 @@ function createSpotPatchMiddleware(options) {
4161
4162
 
4162
4163
  // src/server/source-registration.ts
4163
4164
  import { timingSafeEqual as timingSafeEqual3 } from "crypto";
4164
- import { lstat as lstat4, realpath as realpath6 } from "fs/promises";
4165
+ import { lstat as lstat4, readFile as readFile4, realpath as realpath6 } from "fs/promises";
4165
4166
  import path8 from "path";
4166
- import { createSourceFilter } from "@spotpatch/compiler";
4167
+ import {
4168
+ createDataFlowSourceFilter,
4169
+ createDataFlowSourceVersion,
4170
+ createSourceFilter
4171
+ } from "@spotpatch/compiler";
4172
+ import { DEFAULT_DATA_FLOW_LIMITS as DEFAULT_DATA_FLOW_LIMITS2 } from "@spotpatch/shared";
4167
4173
  import { z as z2 } from "zod";
4168
- var REGISTRATION_BODY_LIMIT_BYTES = 4096;
4174
+ var REGISTRATION_BODY_LIMIT_BYTES = DEFAULT_DATA_FLOW_LIMITS2.protocolRequestMaxBytes;
4169
4175
  var REGISTRATION_IDENTITY_PATTERN = /^[A-Za-z0-9_-]{16,128}$/u;
4176
+ var DATA_FLOW_IDENTITY_PATTERN = /^[A-Za-z0-9_-]{1,128}$/u;
4170
4177
  var INTERNAL_SECRET_HEADER = "x-spotpatch-internal";
4171
4178
  var FORBIDDEN_SOURCE_SEGMENTS = /* @__PURE__ */ new Set([".next", "node_modules"]);
4172
4179
  var registrationRequestSchema = z2.strictObject({
4173
4180
  epoch: z2.string().regex(REGISTRATION_IDENTITY_PATTERN),
4174
- resourcePath: z2.string().min(1).max(3072)
4181
+ resourcePath: z2.string().min(1).max(3072),
4182
+ dataFlow: z2.strictObject({
4183
+ sourceVersion: z2.string().regex(DATA_FLOW_IDENTITY_PATTERN),
4184
+ components: z2.array(
4185
+ z2.strictObject({
4186
+ componentSourceId: z2.string().regex(DATA_FLOW_IDENTITY_PATTERN),
4187
+ line: z2.number().int().positive().max(1e7),
4188
+ column: z2.number().int().positive().max(1e7)
4189
+ })
4190
+ ).max(DEFAULT_DATA_FLOW_LIMITS2.sourceMaxComponents)
4191
+ }).optional()
4175
4192
  });
4176
4193
  function getSingleHeader3(request, name) {
4177
4194
  const value = request.headers[name.toLowerCase()];
@@ -4235,6 +4252,33 @@ async function createSourceRegistrationService(input) {
4235
4252
  }
4236
4253
  const root = await realpath6(input.root);
4237
4254
  const sourceFilter = createSourceFilter(root, input.options);
4255
+ const dataFlowFilter = createDataFlowSourceFilter(root, input.options);
4256
+ const registrationQueues = /* @__PURE__ */ new Map();
4257
+ async function registerCurrentSource(sourcePath, dataFlow) {
4258
+ if (dataFlow === void 0) {
4259
+ return input.registry.register(sourcePath);
4260
+ }
4261
+ let fileId;
4262
+ const previous = registrationQueues.get(sourcePath) ?? Promise.resolve();
4263
+ const current = previous.catch(() => void 0).then(async () => {
4264
+ const currentSource = await readFile4(sourcePath, "utf8");
4265
+ if (createDataFlowSourceVersion(currentSource) !== dataFlow.sourceVersion) {
4266
+ return;
4267
+ }
4268
+ fileId = input.registry.registerDataFlowComponents(
4269
+ sourcePath,
4270
+ dataFlow.sourceVersion,
4271
+ dataFlow.components
4272
+ );
4273
+ });
4274
+ registrationQueues.set(sourcePath, current);
4275
+ await current.finally(() => {
4276
+ if (registrationQueues.get(sourcePath) === current) {
4277
+ registrationQueues.delete(sourcePath);
4278
+ }
4279
+ });
4280
+ return fileId;
4281
+ }
4238
4282
  const handler = (request, response) => {
4239
4283
  const handle = async () => {
4240
4284
  const contentType = getSingleHeader3(request, "content-type")?.split(";", 1)[0]?.trim().toLowerCase();
@@ -4255,16 +4299,18 @@ async function createSourceRegistrationService(input) {
4255
4299
  const sourcePath = await resolveAuthorizedSource(
4256
4300
  root,
4257
4301
  parsed.data.resourcePath,
4258
- (absolutePath) => sourceFilter.shouldTransform(absolutePath, "<")
4302
+ (absolutePath) => parsed.data.dataFlow === void 0 ? sourceFilter.shouldTransform(absolutePath, "<") : dataFlowFilter.shouldTransform(absolutePath, "")
4259
4303
  );
4260
4304
  if (sourcePath === void 0) {
4261
4305
  writeJson3(response, 403, { ok: false });
4262
4306
  return;
4263
4307
  }
4264
- writeJson3(response, 200, {
4265
- epoch: input.registryEpoch,
4266
- fileId: input.registry.register(sourcePath)
4267
- });
4308
+ const fileId = await registerCurrentSource(sourcePath, parsed.data.dataFlow);
4309
+ if (fileId === void 0) {
4310
+ writeJson3(response, 409, { ok: false });
4311
+ return;
4312
+ }
4313
+ writeJson3(response, 200, { epoch: input.registryEpoch, fileId });
4268
4314
  };
4269
4315
  void handle().catch(() => {
4270
4316
  if (!response.headersSent) {