@faicad/faijs 0.22.2 → 0.29.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -28
- package/dist/api/api-namespace.d.ts +5 -5
- package/dist/api/api-namespace.d.ts.map +1 -1
- package/dist/api/api-namespace.js +4 -4
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/appearance.d.ts +138 -0
- package/dist/api/appearance.d.ts.map +1 -0
- package/dist/api/appearance.js +230 -0
- package/dist/api/appearance.js.map +1 -0
- package/dist/api/assert.d.ts +2 -2
- package/dist/api/assert.js +8 -8
- package/dist/api/assert.js.map +1 -1
- package/dist/api/asset.d.ts +1 -1
- package/dist/api/asset.js +2 -2
- package/dist/api/asset.js.map +1 -1
- package/dist/api/boolean.d.ts +1 -1
- package/dist/api/boolean.d.ts.map +1 -1
- package/dist/api/boolean.js +128 -16
- package/dist/api/boolean.js.map +1 -1
- package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
- package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
- package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
- package/dist/api/cadquery-selectors/edge.d.ts +40 -0
- package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/edge.js +70 -0
- package/dist/api/cadquery-selectors/edge.js.map +1 -0
- package/dist/api/cadquery-selectors/entity.d.ts +121 -0
- package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/entity.js +167 -0
- package/dist/api/cadquery-selectors/entity.js.map +1 -0
- package/dist/api/cadquery-selectors/face.d.ts +33 -0
- package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/face.js +353 -0
- package/dist/api/cadquery-selectors/face.js.map +1 -0
- package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
- package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/grammar.js +345 -0
- package/dist/api/cadquery-selectors/grammar.js.map +1 -0
- package/dist/api/cadquery-selectors/index.d.ts +18 -0
- package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/index.js +17 -0
- package/dist/api/cadquery-selectors/index.js.map +1 -0
- package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
- package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/predicates.js +85 -0
- package/dist/api/cadquery-selectors/predicates.js.map +1 -0
- package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
- package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/resolve.js +243 -0
- package/dist/api/cadquery-selectors/resolve.js.map +1 -0
- package/dist/api/cadquery-selectors/types.d.ts +96 -0
- package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
- package/dist/api/cadquery-selectors/types.js +11 -0
- package/dist/api/cadquery-selectors/types.js.map +1 -0
- package/dist/api/chamfer.d.ts +13 -5
- package/dist/api/chamfer.d.ts.map +1 -1
- package/dist/api/chamfer.js +63 -7
- package/dist/api/chamfer.js.map +1 -1
- package/dist/api/compound-geom.d.ts +1 -1
- package/dist/api/compound-geom.js +1 -1
- package/dist/api/compound-geom.js.map +1 -1
- package/dist/api/draft.d.ts +1 -1
- package/dist/api/draft.js +1 -1
- package/dist/api/draft.js.map +1 -1
- package/dist/api/edge-ref.d.ts +1 -1
- package/dist/api/edge-ref.d.ts.map +1 -1
- package/dist/api/edge-ref.js +11 -3
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/engrave.d.ts +1 -1
- package/dist/api/engrave.js +7 -7
- package/dist/api/engrave.js.map +1 -1
- package/dist/api/extrude.d.ts +6 -1
- package/dist/api/extrude.d.ts.map +1 -1
- package/dist/api/extrude.js +59 -5
- package/dist/api/extrude.js.map +1 -1
- package/dist/api/face-ref.d.ts +1 -1
- package/dist/api/face-ref.js +1 -1
- package/dist/api/face-ref.js.map +1 -1
- package/dist/api/feature-repair.d.ts +1 -1
- package/dist/api/feature-repair.js +1 -1
- package/dist/api/feature-repair.js.map +1 -1
- package/dist/api/fillet-variable.d.ts +1 -1
- package/dist/api/fillet-variable.js +1 -1
- package/dist/api/fillet-variable.js.map +1 -1
- package/dist/api/fillet.d.ts +28 -8
- package/dist/api/fillet.d.ts.map +1 -1
- package/dist/api/fillet.js +64 -9
- package/dist/api/fillet.js.map +1 -1
- package/dist/api/geom.d.ts +1 -1
- package/dist/api/geom.js +1 -1
- package/dist/api/geom.js.map +1 -1
- package/dist/api/helix.d.ts +1 -1
- package/dist/api/helix.js +1 -1
- package/dist/api/helix.js.map +1 -1
- package/dist/api/import-brep.d.ts +20 -2
- package/dist/api/import-brep.d.ts.map +1 -1
- package/dist/api/import-brep.js +28 -3
- package/dist/api/import-brep.js.map +1 -1
- package/dist/api/import-step.d.ts +17 -2
- package/dist/api/import-step.d.ts.map +1 -1
- package/dist/api/import-step.js +51 -3
- package/dist/api/import-step.js.map +1 -1
- package/dist/api/index.d.ts +6 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +7 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/internal/compat-op.js +1 -1
- package/dist/api/internal/compat-op.js.map +1 -1
- package/dist/api/internal/mesh-solid-op.d.ts +236 -0
- package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
- package/dist/api/internal/mesh-solid-op.js +352 -0
- package/dist/api/internal/mesh-solid-op.js.map +1 -0
- package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
- package/dist/api/internal/svg-asset-resolver.js +1 -1
- package/dist/api/internal/svg-asset-resolver.js.map +1 -1
- package/dist/api/knurl.d.ts +1 -1
- package/dist/api/knurl.js +2 -2
- package/dist/api/knurl.js.map +1 -1
- package/dist/api/loft.d.ts +1 -1
- package/dist/api/loft.js +1 -1
- package/dist/api/loft.js.map +1 -1
- package/dist/api/measurement/index.d.ts +9 -5
- package/dist/api/measurement/index.d.ts.map +1 -1
- package/dist/api/measurement/index.js +47 -20
- package/dist/api/measurement/index.js.map +1 -1
- package/dist/api/meta.d.ts +93 -0
- package/dist/api/meta.d.ts.map +1 -0
- package/dist/api/meta.js +99 -0
- package/dist/api/meta.js.map +1 -0
- package/dist/api/pattern.d.ts +5 -3
- package/dist/api/pattern.d.ts.map +1 -1
- package/dist/api/pattern.js +32 -4
- package/dist/api/pattern.js.map +1 -1
- package/dist/api/place.d.ts +1 -1
- package/dist/api/place.js +1 -1
- package/dist/api/place.js.map +1 -1
- package/dist/api/primitives.d.ts +1 -1
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +119 -4
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/profile.d.ts +39 -12
- package/dist/api/profile.d.ts.map +1 -1
- package/dist/api/profile.js +4 -4
- package/dist/api/profile.js.map +1 -1
- package/dist/api/reconcile.d.ts +1 -1
- package/dist/api/reconcile.js +1 -1
- package/dist/api/reconcile.js.map +1 -1
- package/dist/api/replicate.d.ts.map +1 -1
- package/dist/api/replicate.js +122 -1
- package/dist/api/replicate.js.map +1 -1
- package/dist/api/screw.d.ts +1 -1
- package/dist/api/screw.js +3 -3
- package/dist/api/screw.js.map +1 -1
- package/dist/api/sdf.d.ts +1 -1
- package/dist/api/sdf.js +2 -2
- package/dist/api/sdf.js.map +1 -1
- package/dist/api/section-by-plane.d.ts +1 -1
- package/dist/api/section-by-plane.d.ts.map +1 -1
- package/dist/api/section-by-plane.js +2 -1
- package/dist/api/section-by-plane.js.map +1 -1
- package/dist/api/shell.d.ts +11 -4
- package/dist/api/shell.d.ts.map +1 -1
- package/dist/api/shell.js +53 -7
- package/dist/api/shell.js.map +1 -1
- package/dist/api/sketch-on-face.d.ts +41 -0
- package/dist/api/sketch-on-face.d.ts.map +1 -1
- package/dist/api/sketch-on-face.js +100 -1
- package/dist/api/sketch-on-face.js.map +1 -1
- package/dist/api/sketch-on-plane.d.ts +7 -5
- package/dist/api/sketch-on-plane.d.ts.map +1 -1
- package/dist/api/sketch-on-plane.js +6 -7
- package/dist/api/sketch-on-plane.js.map +1 -1
- package/dist/api/split-by-plane.d.ts +1 -1
- package/dist/api/split-by-plane.d.ts.map +1 -1
- package/dist/api/split-by-plane.js +2 -1
- package/dist/api/split-by-plane.js.map +1 -1
- package/dist/api/split.d.ts +1 -1
- package/dist/api/split.js +2 -2
- package/dist/api/split.js.map +1 -1
- package/dist/api/sweep.d.ts +1 -1
- package/dist/api/sweep.js +1 -1
- package/dist/api/sweep.js.map +1 -1
- package/dist/api/thicken.d.ts +1 -1
- package/dist/api/thicken.js +1 -1
- package/dist/api/thicken.js.map +1 -1
- package/dist/api/topo-resolve.d.ts +74 -1
- package/dist/api/topo-resolve.d.ts.map +1 -1
- package/dist/api/topo-resolve.js +180 -2
- package/dist/api/topo-resolve.js.map +1 -1
- package/dist/api/transform.d.ts +5 -1
- package/dist/api/transform.d.ts.map +1 -1
- package/dist/api/transform.js +62 -11
- package/dist/api/transform.js.map +1 -1
- package/dist/api/wire.d.ts +1 -1
- package/dist/api/wire.js +1 -1
- package/dist/api/wire.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +9 -7
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +50 -26
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/brep-topology.d.ts +5 -4
- package/dist/brep/brep-topology.d.ts.map +1 -1
- package/dist/brep/brep-topology.js +6 -5
- package/dist/brep/brep-topology.js.map +1 -1
- package/dist/brep/effective-deflection.d.ts +35 -0
- package/dist/brep/effective-deflection.d.ts.map +1 -0
- package/dist/brep/effective-deflection.js +49 -0
- package/dist/brep/effective-deflection.js.map +1 -0
- package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.js +27 -0
- package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
- package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
- package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brepkit.js +46 -1
- package/dist/brep/engine/adapters/brepkit.js.map +1 -1
- package/dist/brep/engine/adapters/occt.d.ts +1 -1
- package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
- package/dist/brep/engine/adapters/occt.js +4 -2
- package/dist/brep/engine/adapters/occt.js.map +1 -1
- package/dist/brep/engine/primitives.d.ts +29 -7
- package/dist/brep/engine/primitives.d.ts.map +1 -1
- package/dist/brep/engine/primitives.js.map +1 -1
- package/dist/brep/engine/registry.d.ts +24 -1
- package/dist/brep/engine/registry.d.ts.map +1 -1
- package/dist/brep/engine/registry.js +24 -0
- package/dist/brep/engine/registry.js.map +1 -1
- package/dist/brep/engine/types.d.ts +54 -3
- package/dist/brep/engine/types.d.ts.map +1 -1
- package/dist/brep/engine/types.js +10 -0
- package/dist/brep/engine/types.js.map +1 -1
- package/dist/brep/export/export-model.d.ts +40 -0
- package/dist/brep/export/export-model.d.ts.map +1 -1
- package/dist/brep/export/export-model.js +274 -30
- package/dist/brep/export/export-model.js.map +1 -1
- package/dist/brep/export/step-meta-header.d.ts +102 -0
- package/dist/brep/export/step-meta-header.d.ts.map +1 -0
- package/dist/brep/export/step-meta-header.js +225 -0
- package/dist/brep/export/step-meta-header.js.map +1 -0
- package/dist/brep/export/step.d.ts +5 -1
- package/dist/brep/export/step.d.ts.map +1 -1
- package/dist/brep/export/step.js +11 -2
- package/dist/brep/export/step.js.map +1 -1
- package/dist/brep/face-evolution.d.ts +1 -1
- package/dist/brep/face-evolution.d.ts.map +1 -1
- package/dist/brep/face-evolution.js +20 -1
- package/dist/brep/face-evolution.js.map +1 -1
- package/dist/brep/handle-bridge.d.ts +1 -1
- package/dist/brep/handle-bridge.js +1 -1
- package/dist/brep/handle-bridge.js.map +1 -1
- package/dist/brep/mesh-solid.d.ts +218 -0
- package/dist/brep/mesh-solid.d.ts.map +1 -0
- package/dist/brep/mesh-solid.js +229 -0
- package/dist/brep/mesh-solid.js.map +1 -0
- package/dist/brep/text/fontRegistry.d.ts +32 -1
- package/dist/brep/text/fontRegistry.d.ts.map +1 -1
- package/dist/brep/text/fontRegistry.js +51 -1
- package/dist/brep/text/fontRegistry.js.map +1 -1
- package/dist/brep/text/text-to-solid.d.ts.map +1 -1
- package/dist/brep/text/text-to-solid.js +8 -3
- package/dist/brep/text/text-to-solid.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +449 -123
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
- package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitWasm.js +10 -0
- package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
- package/dist/browser-host/browser-font-provider.d.ts +12 -0
- package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
- package/dist/browser-host/browser-font-provider.js +25 -0
- package/dist/browser-host/browser-font-provider.js.map +1 -1
- package/dist/browser.d.ts +6 -3
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +10 -3
- package/dist/browser.js.map +1 -1
- package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
- package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
- package/dist/cad-runtime/backend-dispatch.js +119 -4
- package/dist/cad-runtime/backend-dispatch.js.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
- package/dist/cad-runtime/direct-executor.d.ts +15 -3
- package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
- package/dist/cad-runtime/direct-executor.js +33 -1
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/ports.d.ts +3 -3
- package/dist/cad-runtime/ports.d.ts.map +1 -1
- package/dist/cad-runtime/ports.js.map +1 -1
- package/dist/cad-runtime/preview-exec.d.ts +4 -4
- package/dist/cad-runtime/preview-exec.js +2 -2
- package/dist/cad-runtime/preview-exec.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts +42 -7
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +68 -5
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/define-op.d.ts +15 -1
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +73 -2
- package/dist/define-op.js.map +1 -1
- package/dist/env-agnostic.d.ts +2 -2
- package/dist/env-agnostic.d.ts.map +1 -1
- package/dist/env-agnostic.js +1 -1
- package/dist/env-agnostic.js.map +1 -1
- package/dist/geometry2d/adapt.d.ts +39 -4
- package/dist/geometry2d/adapt.d.ts.map +1 -1
- package/dist/geometry2d/adapt.js +14 -3
- package/dist/geometry2d/adapt.js.map +1 -1
- package/dist/geometry2d/blueprint.d.ts +2 -2
- package/dist/geometry2d/blueprint.js +2 -2
- package/dist/geometry2d/blueprint.js.map +1 -1
- package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
- package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
- package/dist/geometry2d/bridge/lift-on-plane.js +65 -12
- package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
- package/dist/geometry2d/bridge/plane.d.ts +17 -0
- package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
- package/dist/geometry2d/bridge/plane.js +22 -0
- package/dist/geometry2d/bridge/plane.js.map +1 -1
- package/dist/geometry2d/curve2d.d.ts +25 -0
- package/dist/geometry2d/curve2d.d.ts.map +1 -1
- package/dist/geometry2d/curve2d.js +41 -5
- package/dist/geometry2d/curve2d.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/io/bytes-node.d.ts +11 -0
- package/dist/io/bytes-node.d.ts.map +1 -0
- package/dist/io/bytes-node.js +28 -0
- package/dist/io/bytes-node.js.map +1 -0
- package/dist/io/bytes.d.ts +33 -0
- package/dist/io/bytes.d.ts.map +1 -0
- package/dist/io/bytes.js +41 -0
- package/dist/io/bytes.js.map +1 -0
- package/dist/io/fai-zip/container-read.d.ts +102 -0
- package/dist/io/fai-zip/container-read.d.ts.map +1 -0
- package/dist/io/fai-zip/container-read.js +305 -0
- package/dist/io/fai-zip/container-read.js.map +1 -0
- package/dist/io/fai-zip/container-write.d.ts +70 -0
- package/dist/io/fai-zip/container-write.d.ts.map +1 -0
- package/dist/io/fai-zip/container-write.js +186 -0
- package/dist/io/fai-zip/container-write.js.map +1 -0
- package/dist/io/fai-zip/container.d.ts +107 -0
- package/dist/io/fai-zip/container.d.ts.map +1 -0
- package/dist/io/fai-zip/container.js +89 -0
- package/dist/io/fai-zip/container.js.map +1 -0
- package/dist/io/fai-zip/index.d.ts +18 -0
- package/dist/io/fai-zip/index.d.ts.map +1 -0
- package/dist/io/fai-zip/index.js +4 -0
- package/dist/io/fai-zip/index.js.map +1 -0
- package/dist/io/index.d.ts +10 -0
- package/dist/io/index.d.ts.map +1 -0
- package/dist/io/index.js +13 -0
- package/dist/io/index.js.map +1 -0
- package/dist/io/zip.d.ts +68 -0
- package/dist/io/zip.d.ts.map +1 -0
- package/dist/io/zip.js +147 -0
- package/dist/io/zip.js.map +1 -0
- package/dist/lang/code-to-args.d.ts +1 -1
- package/dist/lang/code-to-args.js +1 -1
- package/dist/lang/code-to-args.js.map +1 -1
- package/dist/lang/metadata-extractor.d.ts.map +1 -1
- package/dist/lang/metadata-extractor.js +2 -21
- package/dist/lang/metadata-extractor.js.map +1 -1
- package/dist/lang/statement-summary.d.ts +1 -1
- package/dist/lang/statement-summary.js +1 -1
- package/dist/lang/statement-summary.js.map +1 -1
- package/dist/lang/types.d.ts +6 -7
- package/dist/lang/types.d.ts.map +1 -1
- package/dist/lang/types.js +1 -1
- package/dist/lang/types.js.map +1 -1
- package/dist/mesh/index.d.ts +2 -1
- package/dist/mesh/index.d.ts.map +1 -1
- package/dist/mesh/index.js +2 -1
- package/dist/mesh/index.js.map +1 -1
- package/dist/mesh/io.d.ts +13 -0
- package/dist/mesh/io.d.ts.map +1 -1
- package/dist/mesh/io.js +38 -17
- package/dist/mesh/io.js.map +1 -1
- package/dist/mesh/primitives.d.ts.map +1 -1
- package/dist/mesh/primitives.js +41 -6
- package/dist/mesh/primitives.js.map +1 -1
- package/dist/mesh/reconcile.d.ts +1 -1
- package/dist/mesh/reconcile.js +1 -1
- package/dist/mesh/reconcile.js.map +1 -1
- package/dist/mesh/rigid-transform.d.ts +3 -3
- package/dist/mesh/rigid-transform.js +3 -3
- package/dist/mesh/rigid-transform.js.map +1 -1
- package/dist/mesh/stl-unit.d.ts +24 -0
- package/dist/mesh/stl-unit.d.ts.map +1 -0
- package/dist/mesh/stl-unit.js +17 -0
- package/dist/mesh/stl-unit.js.map +1 -0
- package/dist/mesh/threemf-bambu.d.ts +142 -0
- package/dist/mesh/threemf-bambu.d.ts.map +1 -0
- package/dist/mesh/threemf-bambu.js +334 -0
- package/dist/mesh/threemf-bambu.js.map +1 -0
- package/dist/mesh/threemf-loader.d.ts +65 -7
- package/dist/mesh/threemf-loader.d.ts.map +1 -1
- package/dist/mesh/threemf-loader.js +738 -99
- package/dist/mesh/threemf-loader.js.map +1 -1
- package/dist/mesh/threemf-view.d.ts +71 -0
- package/dist/mesh/threemf-view.d.ts.map +1 -0
- package/dist/mesh/threemf-view.js +100 -0
- package/dist/mesh/threemf-view.js.map +1 -0
- package/dist/mesh/types.d.ts +38 -0
- package/dist/mesh/types.d.ts.map +1 -1
- package/dist/mesh/types.js.map +1 -1
- package/dist/node-host/cli.d.ts +44 -6
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +76 -26
- package/dist/node-host/cli.js.map +1 -1
- package/dist/node-host/font-family-index.d.ts +93 -0
- package/dist/node-host/font-family-index.d.ts.map +1 -0
- package/dist/node-host/font-family-index.js +273 -0
- package/dist/node-host/font-family-index.js.map +1 -0
- package/dist/node-host/fs-asset-resolver.d.ts +8 -3
- package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
- package/dist/node-host/fs-asset-resolver.js +13 -5
- package/dist/node-host/fs-asset-resolver.js.map +1 -1
- package/dist/node-host/index.d.ts +8 -0
- package/dist/node-host/index.d.ts.map +1 -1
- package/dist/node-host/index.js +1 -0
- package/dist/node-host/index.js.map +1 -1
- package/dist/node-host/node-font-provider.d.ts +28 -0
- package/dist/node-host/node-font-provider.d.ts.map +1 -1
- package/dist/node-host/node-font-provider.js +49 -0
- package/dist/node-host/node-font-provider.js.map +1 -1
- package/dist/node.d.ts +1 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +1 -0
- package/dist/node.js.map +1 -1
- package/dist/occt-kernel/highLevelApi.d.ts +4 -1
- package/dist/occt-kernel/highLevelApi.d.ts.map +1 -1
- package/dist/occt-kernel/highLevelApi.js +4 -2
- package/dist/occt-kernel/highLevelApi.js.map +1 -1
- package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
- package/dist/occt-kernel/occt-primitives.js +36 -3
- package/dist/occt-kernel/occt-primitives.js.map +1 -1
- package/dist/occt-kernel/occtKernel.d.ts +19 -14
- package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
- package/dist/occt-kernel/occtKernel.js +19 -32
- package/dist/occt-kernel/occtKernel.js.map +1 -1
- package/dist/occt-kernel/stepColorParser.d.ts +18 -0
- package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
- package/dist/occt-kernel/stepColorParser.js +38 -0
- package/dist/occt-kernel/stepColorParser.js.map +1 -1
- package/dist/occt-kernel/stepMetaParser.d.ts +44 -0
- package/dist/occt-kernel/stepMetaParser.d.ts.map +1 -0
- package/dist/occt-kernel/stepMetaParser.js +166 -0
- package/dist/occt-kernel/stepMetaParser.js.map +1 -0
- package/dist/occt-kernel/topologyExt.d.ts +1 -1
- package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
- package/dist/occt-kernel/topologyExt.js +4 -5
- package/dist/occt-kernel/topologyExt.js.map +1 -1
- package/dist/primitives/text/cjk-font.d.ts +2 -15
- package/dist/primitives/text/cjk-font.d.ts.map +1 -1
- package/dist/primitives/text/cjk-font.js +13 -1
- package/dist/primitives/text/cjk-font.js.map +1 -1
- package/dist/runtime-state.d.ts +85 -9
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +72 -2
- package/dist/runtime-state.js.map +1 -1
- package/dist/sdk.d.ts +3 -3
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +5 -5
- package/dist/sdk.js.map +1 -1
- package/dist/shape.d.ts +108 -5
- package/dist/shape.d.ts.map +1 -1
- package/dist/shape.js +130 -3
- package/dist/shape.js.map +1 -1
- package/dist/step/stepMetaParser.d.ts +55 -0
- package/dist/step/stepMetaParser.d.ts.map +1 -0
- package/dist/step/stepMetaParser.js +177 -0
- package/dist/step/stepMetaParser.js.map +1 -0
- package/dist/topology/naming/lineage.d.ts +6 -0
- package/dist/topology/naming/lineage.d.ts.map +1 -1
- package/dist/topology/naming/lineage.js +8 -0
- package/dist/topology/naming/lineage.js.map +1 -1
- package/dist/topology/naming/resolve-edge.d.ts +20 -1
- package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
- package/dist/topology/naming/resolve-edge.js +54 -20
- package/dist/topology/naming/resolve-edge.js.map +1 -1
- package/dist/weapp.d.ts +6 -2
- package/dist/weapp.d.ts.map +1 -1
- package/dist/weapp.js +7 -1
- package/dist/weapp.js.map +1 -1
- package/package.json +19 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-read.js","sourceRoot":"","sources":["../../../src/io/fai-zip/container-read.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified `.fai.zip` read API (docs/fai-zip-format.md §4–§9).\n *\n * Environment-independent by constraint: reading goes through `io/zip.ts`\n * (`readZipEntries`) plus JSON parsing — no `node:*`, no DOM, no fs, and no\n * direct ZIP library. Web workers, the weapp worker and node share this code.\n *\n * Contract highlights (spec §9 Reader obligations):\n * - a missing/malformed manifest, `format !== 3`, a malformed `models` array,\n * a missing entry, a missing named data member and a duplicate asset key are\n * all errors carrying the offending value;\n * - entry selection is `active` or `models[0]` — never a file-name heuristic;\n * - members outside the table (§3), unknown manifest fields and unknown\n * data-member keys are ignored, never errors, never decision inputs.\n */\nimport { readZipEntries, type ZipReadOptions } from '../zip'\nimport type { ProjectLoader } from '../../cad-runtime/ports'\nimport {\n assetKeyOf,\n assertDataMemberPath,\n assertModelMemberPath,\n assertSafeMemberPath,\n decodeMemberText,\n type ContainerAssetEntries,\n type ContainerManifest,\n type ContainerModel,\n} from './container'\n\n/** openContainer options. */\nexport interface OpenContainerOptions {\n /** override `manifest.active`; default = `manifest.active`, else `models[0]` */\n modelId?: string\n /** override the `io/zip.ts` read caps (maxEntries / maxTotalBytes) */\n caps?: ZipReadOptions\n}\n\n/** openContainer result: manifest, active model, loader and payloads. */\nexport interface OpenContainerResult {\n manifest: ContainerManifest\n activeModel: ContainerModel\n /** project loader over the container's module graph (listModules/readSource) */\n loader: ProjectLoader\n files: Record<string, Uint8Array>\n assets: Record<string, Uint8Array>\n}\n\n/** Unzipped members, keyed by container path. */\ntype MemberMap = Map<string, Uint8Array>\n\n/** Path prefix of every model script member. */\nconst MODEL_PREFIX = 'model/'\n/** Path prefix of the imported-file payloads. */\nconst FILES_PREFIX = 'files/'\n/** Path prefix of the script-consumed payloads. */\nconst ASSETS_PREFIX = 'assets/'\n\n/**\n * Unpack the archive; a non-ZIP input is a hard error carrying the original\n * failure as `cause`. Caps violations keep `io/zip.ts`'s wording.\n */\nfunction unzipMembers(bytes: Uint8Array, caps?: ZipReadOptions): MemberMap {\n try {\n return readZipEntries(bytes, caps)\n } catch (e) {\n const inner = (e instanceof Error ? e.message : String(e)).replace(/^zip read failed: /, '')\n const err = new Error(`[fai-zip] cannot open container as ZIP: ${inner}`)\n ;(err as Error & { cause?: unknown }).cause = e\n throw err\n }\n}\n\n/** Normalize a manifest field error into one message naming the offending value. */\nfunction manifestError(reason: string, value?: unknown): Error {\n const shown = value === undefined ? '' : ` (observed: ${JSON.stringify(value)})`\n return new Error(`[fai-zip] invalid manifest: ${reason}${shown}`)\n}\n\n/**\n * Read and validate the container manifest from already-unpacked members.\n * @param members the unpacked container members\n * @returns the validated manifest\n */\nfunction readManifestFrom(members: MemberMap): ContainerManifest {\n const raw = members.get('manifest.json')\n if (raw === undefined) throw new Error('[fai-zip] invalid manifest: missing manifest.json — not a .fai.zip container')\n let parsed: unknown\n try {\n parsed = JSON.parse(decodeMemberText(raw))\n } catch (e) {\n throw new Error(`[fai-zip] invalid manifest: manifest.json is not valid JSON: ${e instanceof Error ? e.message : String(e)}`, { cause: e })\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw manifestError('manifest.json must be a JSON object')\n }\n const manifest = parsed as Record<string, unknown>\n\n if (manifest.format !== 3) {\n throw manifestError('format must be the integer 3 (this revision); no other value is interpretable', manifest.format)\n }\n if (manifest.units !== 'mm') {\n throw manifestError('units must be \"mm\"', manifest.units)\n }\n if (!Array.isArray(manifest.models) || manifest.models.length === 0) {\n throw manifestError('models must be a non-empty array', manifest.models)\n }\n\n const models = manifest.models as unknown[]\n const seenIds = new Set<string>()\n const seenEntries = new Set<string>()\n const normalized: ContainerModel[] = []\n for (let i = 0; i < models.length; i++) {\n const m = models[i]\n if (typeof m !== 'object' || m === null || Array.isArray(m)) {\n throw manifestError(`models[${i}] must be an object`, m)\n }\n const rec = m as Record<string, unknown>\n const id = typeof rec.id === 'string' ? rec.id : ''\n if (id === '') throw manifestError(`models[${i}].id must be a non-empty string`, rec.id)\n if (id.includes('/') || id.includes('\\\\')) throw manifestError(`models[${i}].id must not contain \"/\" or \"\\\\\"`, id)\n if (seenIds.has(id)) throw manifestError('models[].id must be unique', id)\n seenIds.add(id)\n\n const entry = typeof rec.entry === 'string' ? rec.entry : ''\n if (entry === '') throw manifestError(`models[${i}].entry must be a non-empty string`, rec.entry)\n assertModelMemberPath(entry, `models[${i}].entry`)\n if (seenEntries.has(entry)) throw manifestError('models[].entry must be unique', entry)\n seenEntries.add(entry)\n if (!members.has(entry)) {\n throw manifestError(`models[${i}].entry does not exist in the container`, entry)\n }\n\n const data = typeof rec.data === 'string' ? rec.data : undefined\n if (data !== undefined) {\n assertSafeMemberPath(data, `models[${i}].data`)\n if (!members.has(data)) {\n throw manifestError(`models[${i}].data names a member that does not exist`, data)\n }\n }\n\n normalized.push({\n id,\n entry,\n ...(typeof rec.label === 'string' ? { label: rec.label } : {}),\n ...(data !== undefined ? { data } : {}),\n })\n }\n\n let active: string | undefined\n if (manifest.active !== undefined) {\n if (typeof manifest.active !== 'string' || !seenIds.has(manifest.active)) {\n throw manifestError('active must equal some models[].id', manifest.active)\n }\n active = manifest.active\n }\n\n return {\n format: 3,\n units: 'mm',\n models: normalized,\n ...(active !== undefined ? { active } : {}),\n ...(typeof manifest.createdAt === 'string' ? { createdAt: manifest.createdAt } : {}),\n ...(typeof manifest.appVersion === 'string' ? { appVersion: manifest.appVersion } : {}),\n ...(typeof manifest.label === 'string' ? { label: manifest.label } : {}),\n ...(typeof manifest.source === 'object' && manifest.source !== null ? { source: manifest.source as ContainerManifest['source'] } : {}),\n }\n}\n\n/**\n * Collect the payload bytes of already-unpacked members.\n * Keys are unique across `files/**` and `assets/**` together (spec §7.1);\n * a duplicate key is an error rather than a pick.\n * @param members the unpacked container members\n * @returns the payload entries keyed by asset key\n */\nfunction readAssetEntriesFrom(members: MemberMap): ContainerAssetEntries {\n const files: Record<string, Uint8Array> = {}\n const assets: Record<string, Uint8Array> = {}\n const claimed = new Set<string>()\n for (const [path, body] of members) {\n const prefix = path.startsWith(FILES_PREFIX)\n ? FILES_PREFIX\n : path.startsWith(ASSETS_PREFIX)\n ? ASSETS_PREFIX\n : undefined\n if (prefix === undefined) continue\n const key = assetKeyOf(path, prefix)\n if (claimed.has(key)) throw new Error(`[fai-zip] duplicate asset key across files//assets/: \"${key}\"`)\n claimed.add(key)\n if (prefix === FILES_PREFIX) files[key] = body\n else assets[key] = body\n }\n return { files, assets }\n}\n\n/**\n * Read and validate the container manifest (spec §4).\n * @param bytes the .fai.zip archive bytes\n * @returns the validated manifest\n * @throws when the archive is not a ZIP, the manifest is missing/malformed,\n * `format !== 3`, `units !== \"mm\"`, `models` is empty/malformed, ids/entries\n * are duplicated, an entry is not under `model/` or does not exist, `active`\n * is not in `models[].id`, or a named `data` member does not exist.\n */\nexport function readManifest(bytes: Uint8Array): ContainerManifest {\n return readManifestFrom(unzipMembers(bytes))\n}\n\n/**\n * List the container models (validated). Same validation as readManifest.\n * @param bytes the .fai.zip archive bytes\n * @returns the validated model list\n */\nexport function listModels(bytes: Uint8Array): ContainerModel[] {\n return readManifest(bytes).models\n}\n\n/**\n * List every module under `model/` (keys relative to `model/`, sorted).\n * Members outside the table are ignored (§3), never an error.\n * @param bytes the .fai.zip archive bytes\n * @returns module keys relative to `model/`, sorted\n */\nexport function listModules(bytes: Uint8Array): string[] {\n return listModulesFrom(unzipMembers(bytes))\n}\n\n/** Module keys (relative to `model/`, sorted) of already-unpacked members. */\nfunction listModulesFrom(members: MemberMap): string[] {\n const keys: string[] = []\n for (const path of members.keys()) {\n if (path.startsWith(MODEL_PREFIX) && path.endsWith('.fai.js') && path.length > MODEL_PREFIX.length) {\n keys.push(path.slice(MODEL_PREFIX.length))\n }\n }\n return keys.sort()\n}\n\n/**\n * Read one module's source text by module key (relative to `model/`).\n * @param bytes the .fai.zip archive bytes\n * @param key the module key relative to `model/` (e.g. `main.fai.js`)\n * @returns the module source text\n * @throws for a key outside `model/` or that does not exist\n */\nexport function readModule(bytes: Uint8Array, key: string): string {\n if (typeof key !== 'string' || key === '') {\n throw new Error('[fai-zip] readModule: key must be a non-empty string')\n }\n assertSafeMemberPath(key, 'readModule key')\n if (!key.endsWith('.fai.js')) {\n throw new Error(`[fai-zip] readModule: key must name a module under model/ (ends with .fai.js): \"${key}\"`)\n }\n const member = unzipMembers(bytes).get(MODEL_PREFIX + key)\n if (member === undefined) {\n throw new Error(`[fai-zip] readModule: module \"${key}\" does not exist under model/`)\n }\n return decodeMemberText(member)\n}\n\n/**\n * Read one model data member's JSON text by member path (e.g. `data/main.json`).\n *\n * The path must be exactly what `models[].data` declares (spec §4): a safe,\n * relative member under `data/` ending with `.json`. Content is validated to\n * parse as JSON — the editor keeps data members pure JSON (§6.1), so a\n * non-JSON member is a format violation and an error, never a silent skip.\n *\n * @param bytes the .fai.zip archive bytes\n * @param memberPath the member path named by `models[].data`\n * @returns the raw JSON text\n * @throws for a non-string/unsafe path, a path outside `data/`, a missing\n * member, or content that does not parse as JSON\n */\nexport function readDataMember(bytes: Uint8Array, memberPath: string): string {\n if (typeof memberPath !== 'string' || memberPath === '') {\n throw new Error('[fai-zip] readDataMember: memberPath must be a non-empty string')\n }\n assertDataMemberPath(memberPath, 'readDataMember path')\n const member = unzipMembers(bytes).get(memberPath)\n if (member === undefined) {\n throw new Error(`[fai-zip] readDataMember: member \"${memberPath}\" does not exist in the container`)\n }\n const text = decodeMemberText(member)\n try {\n JSON.parse(text)\n } catch (e) {\n throw new Error(`[fai-zip] readDataMember: \"${memberPath}\" is not valid JSON: ${e instanceof Error ? e.message : String(e)}`, { cause: e })\n }\n return text\n}\n\n/**\n * Collect the payload bytes of a container.\n * Keys are unique across `files/**` and `assets/**` together (spec §7.1);\n * a duplicate key is an error rather than a pick.\n * @param bytes the .fai.zip archive bytes\n * @returns the payload entries keyed by asset key\n */\nexport function readAssetEntries(bytes: Uint8Array): ContainerAssetEntries {\n return readAssetEntriesFrom(unzipMembers(bytes))\n}\n\n/**\n * Host entry point: open a container and return the manifest, the active\n * model and a ProjectLoader over its module graph, plus the payloads.\n *\n * The archive is unpacked exactly once for the whole call.\n *\n * @param bytes the .fai.zip archive bytes\n * @param opts optional active-model override and `io/zip.ts` read caps\n * @returns manifest, active model, project loader and payload entries\n * @throws when the container is invalid, the requested model id is unknown, or\n * the read caps are exceeded\n */\nexport function openContainer(bytes: Uint8Array, opts: OpenContainerOptions = {}): OpenContainerResult {\n const members = unzipMembers(bytes, opts.caps)\n const manifest = readManifestFrom(members)\n\n const activeModel: ContainerModel = (() => {\n if (opts.modelId === undefined) {\n const byActive = manifest.models.find((m) => m.id === manifest.active)\n return byActive ?? manifest.models[0]\n }\n const byParam = manifest.models.find((m) => m.id === opts.modelId)\n if (byParam === undefined) {\n throw new Error(`[fai-zip] openContainer: model \"${opts.modelId}\" is not in models[]`)\n }\n return byParam\n })()\n\n const keys = listModulesFrom(members)\n\n const loader: ProjectLoader = {\n listModules: () => [...keys],\n readSource: async (moduleKey) => {\n const member = members.get(MODEL_PREFIX + moduleKey)\n if (member === undefined) {\n throw new Error(`[fai-zip] loader: module \"${moduleKey}\" does not exist under model/`)\n }\n return decodeMemberText(member)\n },\n }\n\n const { files, assets } = readAssetEntriesFrom(members)\n return { manifest, activeModel, loader, files, assets }\n}\n"]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type ContainerManifest, type ContainerModel } from './container.js';
|
|
2
|
+
/** Assembly input of a container: no producer concept, only format concepts. */
|
|
3
|
+
export interface ContainerAssembly {
|
|
4
|
+
/** `manifest.models` — the complete model list (spec §4) */
|
|
5
|
+
models: ContainerModel[];
|
|
6
|
+
/** `manifest.active`; must equal some `models[].id` when present */
|
|
7
|
+
active?: string;
|
|
8
|
+
/** display-only manifest fields plus §8.2 conversion provenance */
|
|
9
|
+
meta?: {
|
|
10
|
+
createdAt?: string;
|
|
11
|
+
appVersion?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
source?: ContainerManifest['source'];
|
|
14
|
+
};
|
|
15
|
+
/** `model/**` members: full container path → source text. Every `models[].entry` must be present */
|
|
16
|
+
modules: Record<string, string>;
|
|
17
|
+
/** `data/**` members: full container path → JSON text (spec §6) */
|
|
18
|
+
dataMembers: Record<string, string>;
|
|
19
|
+
/** `files/**` payloads: fileId → bytes. Written as `files/<fileId>.bin` */
|
|
20
|
+
files: Record<string, Uint8Array>;
|
|
21
|
+
/** `assets/**` payloads: full container path → bytes (e.g. `assets/bracket.brp`) */
|
|
22
|
+
assets: Record<string, Uint8Array>;
|
|
23
|
+
/** producer-defined members (spec §3, e.g. `mapping.json`, `freecad/**`), written as-is */
|
|
24
|
+
producerMembers?: Record<string, Uint8Array>;
|
|
25
|
+
}
|
|
26
|
+
/** Result of `writeContainer`. */
|
|
27
|
+
export interface WriteContainerResult {
|
|
28
|
+
/** the assembled container bytes */
|
|
29
|
+
bytes: Uint8Array;
|
|
30
|
+
/** the manifest that was serialized into the container */
|
|
31
|
+
manifest: ContainerManifest;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build and validate the container manifest — the single implementation of the
|
|
35
|
+
* §4 schema.
|
|
36
|
+
*
|
|
37
|
+
* Structural only: it cannot check that `models[].entry` and `models[].data`
|
|
38
|
+
* resolve to emitted members, because it never sees the members. That is
|
|
39
|
+
* `writeContainer`'s job, and it is why conversion pipelines that legitimately
|
|
40
|
+
* assemble a container in two passes can still reuse this function.
|
|
41
|
+
*
|
|
42
|
+
* @param input the model list, the optional active id and display metadata
|
|
43
|
+
* @returns the manifest, with `format: 3` and `units: "mm"` fixed
|
|
44
|
+
* @throws when `models` is empty, an id/entry is empty, unsafe or duplicated,
|
|
45
|
+
* an `entry` is not a module path under `model/` ending with `.fai.js`, a
|
|
46
|
+
* `data` is not a JSON path under `data/`, or `active` names no model
|
|
47
|
+
*/
|
|
48
|
+
export declare function createManifest(input: Pick<ContainerAssembly, 'models' | 'active' | 'meta'>): ContainerManifest;
|
|
49
|
+
/**
|
|
50
|
+
* Assemble a container from an assembly, enforcing spec §10 before writing any
|
|
51
|
+
* bytes.
|
|
52
|
+
*
|
|
53
|
+
* Enforced (each throws, never silently produces an unreconstructable
|
|
54
|
+
* container):
|
|
55
|
+
* 1. `models` is non-empty, ids and entries are unique (`createManifest`);
|
|
56
|
+
* 2. every `models[].entry` is emitted in `modules`;
|
|
57
|
+
* 3. every `models[].data` is emitted in `dataMembers`;
|
|
58
|
+
* 4. `active`, when present, equals some `models[].id` (`createManifest`);
|
|
59
|
+
* 5. asset keys are unique across `files/**`, `assets/**` and any
|
|
60
|
+
* producer-defined member in those namespaces (spec §7.1) — a fileId that
|
|
61
|
+
* would not survive the base-name key rule is an error, not a silent rename;
|
|
62
|
+
* 6. every `entry`/`data`/module/asset path is a safe relative member path in
|
|
63
|
+
* its namespace, and no path is emitted twice.
|
|
64
|
+
*
|
|
65
|
+
* @param assembly the assembly input (§3.4)
|
|
66
|
+
* @returns the container bytes and the manifest that was written
|
|
67
|
+
* @throws when any of the obligations above is violated
|
|
68
|
+
*/
|
|
69
|
+
export declare function writeContainer(assembly: ContainerAssembly): WriteContainerResult;
|
|
70
|
+
//# sourceMappingURL=container-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-write.d.ts","sourceRoot":"","sources":["../../../src/io/fai-zip/container-write.ts"],"names":[],"mappings":"AAgBA,OAAO,EAML,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAA;AAEpB,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAA;KACrC,CAAA;IACD,oGAAoG;IACpG,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACjC,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IAClC,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAC7C;AAED,kCAAkC;AAClC,MAAM,WAAW,oBAAoB;IACnC,oCAAoC;IACpC,KAAK,EAAE,UAAU,CAAA;IACjB,0DAA0D;IAC1D,QAAQ,EAAE,iBAAiB,CAAA;CAC5B;AAKD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC,GAAG,iBAAiB,CAoD9G;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB,CAuFhF"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified `.fai.zip` write API (docs/fai-zip-format.md §10, Writer obligations).
|
|
3
|
+
*
|
|
4
|
+
* The input is an *assembly* — pure format concepts plus opaque
|
|
5
|
+
* producer-defined members (§3). Nothing here knows about FCStd, editors or
|
|
6
|
+
* filesystems.
|
|
7
|
+
*
|
|
8
|
+
* Environment-independent: ZIP bytes go through `io/zip.ts`, text goes through
|
|
9
|
+
* the UTF-8 codec in `./container.js`. No `node:*`, no fflate, no fs.
|
|
10
|
+
*
|
|
11
|
+
* The point of this layer is that a container which a reader cannot
|
|
12
|
+
* reconstruct is never produced: every §10 obligation that can be checked
|
|
13
|
+
* statically is checked here and throws. A thrown error is always preferable
|
|
14
|
+
* to a container with a dangling reference (spec §10.7, fail loudly).
|
|
15
|
+
*/
|
|
16
|
+
import { writeZipEntries } from '../zip.js';
|
|
17
|
+
import { assetKeyOf, assertDataMemberPath, assertModelMemberPath, assertSafeMemberPath, encodeMemberText, } from './container.js';
|
|
18
|
+
const FILES_PREFIX = 'files/';
|
|
19
|
+
const ASSETS_PREFIX = 'assets/';
|
|
20
|
+
/**
|
|
21
|
+
* Build and validate the container manifest — the single implementation of the
|
|
22
|
+
* §4 schema.
|
|
23
|
+
*
|
|
24
|
+
* Structural only: it cannot check that `models[].entry` and `models[].data`
|
|
25
|
+
* resolve to emitted members, because it never sees the members. That is
|
|
26
|
+
* `writeContainer`'s job, and it is why conversion pipelines that legitimately
|
|
27
|
+
* assemble a container in two passes can still reuse this function.
|
|
28
|
+
*
|
|
29
|
+
* @param input the model list, the optional active id and display metadata
|
|
30
|
+
* @returns the manifest, with `format: 3` and `units: "mm"` fixed
|
|
31
|
+
* @throws when `models` is empty, an id/entry is empty, unsafe or duplicated,
|
|
32
|
+
* an `entry` is not a module path under `model/` ending with `.fai.js`, a
|
|
33
|
+
* `data` is not a JSON path under `data/`, or `active` names no model
|
|
34
|
+
*/
|
|
35
|
+
export function createManifest(input) {
|
|
36
|
+
const { models, active, meta = {} } = input;
|
|
37
|
+
if (!Array.isArray(models) || models.length === 0) {
|
|
38
|
+
throw new Error('[fai-zip] createManifest: models must be a non-empty array');
|
|
39
|
+
}
|
|
40
|
+
const seenIds = new Set();
|
|
41
|
+
const seenEntries = new Set();
|
|
42
|
+
const normalized = [];
|
|
43
|
+
for (let i = 0; i < models.length; i++) {
|
|
44
|
+
const m = models[i];
|
|
45
|
+
const id = typeof m.id === 'string' ? m.id : '';
|
|
46
|
+
if (id === '')
|
|
47
|
+
throw new Error(`[fai-zip] createManifest: models[${i}].id must be a non-empty string`);
|
|
48
|
+
if (id.includes('/') || id.includes('\\')) {
|
|
49
|
+
throw new Error(`[fai-zip] createManifest: models[${i}].id must not contain "/" or "\\": "${id}"`);
|
|
50
|
+
}
|
|
51
|
+
if (seenIds.has(id))
|
|
52
|
+
throw new Error(`[fai-zip] createManifest: models[].id must be unique: "${id}"`);
|
|
53
|
+
seenIds.add(id);
|
|
54
|
+
if (typeof m.entry !== 'string' || m.entry === '') {
|
|
55
|
+
throw new Error(`[fai-zip] createManifest: models[${i}].entry must be a non-empty string`);
|
|
56
|
+
}
|
|
57
|
+
assertModelMemberPath(m.entry, `createManifest: models[${i}].entry`);
|
|
58
|
+
if (seenEntries.has(m.entry)) {
|
|
59
|
+
throw new Error(`[fai-zip] createManifest: models[].entry must be unique: "${m.entry}"`);
|
|
60
|
+
}
|
|
61
|
+
seenEntries.add(m.entry);
|
|
62
|
+
if (m.data !== undefined)
|
|
63
|
+
assertDataMemberPath(m.data, `createManifest: models[${i}].data`);
|
|
64
|
+
normalized.push({
|
|
65
|
+
id,
|
|
66
|
+
entry: m.entry,
|
|
67
|
+
...(m.label !== undefined ? { label: m.label } : {}),
|
|
68
|
+
...(m.data !== undefined ? { data: m.data } : {}),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (active !== undefined && !seenIds.has(active)) {
|
|
72
|
+
throw new Error(`[fai-zip] createManifest: active must equal some models[].id: "${active}"`);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
format: 3,
|
|
76
|
+
units: 'mm',
|
|
77
|
+
models: normalized,
|
|
78
|
+
...(active !== undefined ? { active } : {}),
|
|
79
|
+
...(meta.createdAt !== undefined ? { createdAt: meta.createdAt } : {}),
|
|
80
|
+
...(meta.appVersion !== undefined ? { appVersion: meta.appVersion } : {}),
|
|
81
|
+
...(meta.label !== undefined ? { label: meta.label } : {}),
|
|
82
|
+
...(meta.source !== undefined ? { source: meta.source } : {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Assemble a container from an assembly, enforcing spec §10 before writing any
|
|
87
|
+
* bytes.
|
|
88
|
+
*
|
|
89
|
+
* Enforced (each throws, never silently produces an unreconstructable
|
|
90
|
+
* container):
|
|
91
|
+
* 1. `models` is non-empty, ids and entries are unique (`createManifest`);
|
|
92
|
+
* 2. every `models[].entry` is emitted in `modules`;
|
|
93
|
+
* 3. every `models[].data` is emitted in `dataMembers`;
|
|
94
|
+
* 4. `active`, when present, equals some `models[].id` (`createManifest`);
|
|
95
|
+
* 5. asset keys are unique across `files/**`, `assets/**` and any
|
|
96
|
+
* producer-defined member in those namespaces (spec §7.1) — a fileId that
|
|
97
|
+
* would not survive the base-name key rule is an error, not a silent rename;
|
|
98
|
+
* 6. every `entry`/`data`/module/asset path is a safe relative member path in
|
|
99
|
+
* its namespace, and no path is emitted twice.
|
|
100
|
+
*
|
|
101
|
+
* @param assembly the assembly input (§3.4)
|
|
102
|
+
* @returns the container bytes and the manifest that was written
|
|
103
|
+
* @throws when any of the obligations above is violated
|
|
104
|
+
*/
|
|
105
|
+
export function writeContainer(assembly) {
|
|
106
|
+
const { modules, dataMembers, files, assets, producerMembers = {} } = assembly;
|
|
107
|
+
const manifest = createManifest(assembly);
|
|
108
|
+
const members = new Map();
|
|
109
|
+
const claimedKeys = new Map();
|
|
110
|
+
/** Record an asset key; a second member claiming it is an error (spec §7.1). */
|
|
111
|
+
const claim = (key, path) => {
|
|
112
|
+
const prev = claimedKeys.get(key);
|
|
113
|
+
if (prev !== undefined) {
|
|
114
|
+
throw new Error(`[fai-zip] writeContainer: duplicate asset key "${key}" (members "${prev}" and "${path}")`);
|
|
115
|
+
}
|
|
116
|
+
claimedKeys.set(key, path);
|
|
117
|
+
};
|
|
118
|
+
/** Add one member; a duplicate member path is an error. */
|
|
119
|
+
const put = (path, body) => {
|
|
120
|
+
if (members.has(path)) {
|
|
121
|
+
throw new Error(`[fai-zip] writeContainer: duplicate member path "${path}"`);
|
|
122
|
+
}
|
|
123
|
+
members.set(path, body);
|
|
124
|
+
};
|
|
125
|
+
// manifest.json — always first, always present (spec §10.1)
|
|
126
|
+
put('manifest.json', encodeMemberText(JSON.stringify(manifest, null, 2)));
|
|
127
|
+
// model/** — every declared entry must be delivered (spec §10.2, §10.3)
|
|
128
|
+
for (const [path, source] of Object.entries(modules)) {
|
|
129
|
+
assertModelMemberPath(path, 'writeContainer: modules key');
|
|
130
|
+
put(path, encodeMemberText(source));
|
|
131
|
+
}
|
|
132
|
+
for (const m of manifest.models) {
|
|
133
|
+
if (!members.has(m.entry)) {
|
|
134
|
+
throw new Error(`[fai-zip] writeContainer: models[].entry "${m.entry}" has no module in the assembly`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// data/** — a declared data member must be delivered, and must be JSON (spec §6.1)
|
|
138
|
+
for (const [path, json] of Object.entries(dataMembers)) {
|
|
139
|
+
assertDataMemberPath(path, 'writeContainer: dataMembers key');
|
|
140
|
+
try {
|
|
141
|
+
JSON.parse(json);
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
throw new Error(`[fai-zip] writeContainer: data member "${path}" is not valid JSON: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
145
|
+
}
|
|
146
|
+
put(path, encodeMemberText(json));
|
|
147
|
+
}
|
|
148
|
+
for (const m of manifest.models) {
|
|
149
|
+
if (m.data !== undefined && !members.has(m.data)) {
|
|
150
|
+
throw new Error(`[fai-zip] writeContainer: models[].data "${m.data}" has no member in the assembly`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// files/** — keyed by fileId, stored as files/<fileId>.bin so the key
|
|
154
|
+
// round-trips through the base-name rule (spec §7). A fileId containing a
|
|
155
|
+
// separator would be silently re-keyed on read, so it is rejected here.
|
|
156
|
+
for (const [fileId, body] of Object.entries(files)) {
|
|
157
|
+
if (fileId === '' || fileId.includes('/') || fileId.includes('\\')) {
|
|
158
|
+
throw new Error(`[fai-zip] writeContainer: fileId must be a non-empty base name without separators: "${fileId}"`);
|
|
159
|
+
}
|
|
160
|
+
const path = `${FILES_PREFIX}${fileId}.bin`;
|
|
161
|
+
put(path, body);
|
|
162
|
+
claim(assetKeyOf(path, FILES_PREFIX), path);
|
|
163
|
+
}
|
|
164
|
+
// assets/** — the key is the base name, so two paths may collide (spec §7.1)
|
|
165
|
+
for (const [path, body] of Object.entries(assets)) {
|
|
166
|
+
assertSafeMemberPath(path, 'writeContainer: assets key');
|
|
167
|
+
if (!path.startsWith(ASSETS_PREFIX)) {
|
|
168
|
+
throw new Error(`[fai-zip] writeContainer: assets key must be under assets/: "${path}"`);
|
|
169
|
+
}
|
|
170
|
+
put(path, body);
|
|
171
|
+
claim(assetKeyOf(path, ASSETS_PREFIX), path);
|
|
172
|
+
}
|
|
173
|
+
// producer-defined members (spec §3) — opaque payload, but they still live
|
|
174
|
+
// in the archive, so a member dropped under files//assets/ takes part in the
|
|
175
|
+
// key uniqueness rule whether or not the producer thought of it that way.
|
|
176
|
+
for (const [path, body] of Object.entries(producerMembers)) {
|
|
177
|
+
assertSafeMemberPath(path, 'writeContainer: producerMembers key');
|
|
178
|
+
put(path, body);
|
|
179
|
+
if (path.startsWith(FILES_PREFIX))
|
|
180
|
+
claim(assetKeyOf(path, FILES_PREFIX), path);
|
|
181
|
+
else if (path.startsWith(ASSETS_PREFIX))
|
|
182
|
+
claim(assetKeyOf(path, ASSETS_PREFIX), path);
|
|
183
|
+
}
|
|
184
|
+
return { bytes: writeZipEntries(Object.fromEntries(members)), manifest };
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=container-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-write.js","sourceRoot":"","sources":["../../../src/io/fai-zip/container-write.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified `.fai.zip` write API (docs/fai-zip-format.md §10, Writer obligations).\n *\n * The input is an *assembly* — pure format concepts plus opaque\n * producer-defined members (§3). Nothing here knows about FCStd, editors or\n * filesystems.\n *\n * Environment-independent: ZIP bytes go through `io/zip.ts`, text goes through\n * the UTF-8 codec in `./container.js`. No `node:*`, no fflate, no fs.\n *\n * The point of this layer is that a container which a reader cannot\n * reconstruct is never produced: every §10 obligation that can be checked\n * statically is checked here and throws. A thrown error is always preferable\n * to a container with a dangling reference (spec §10.7, fail loudly).\n */\nimport { writeZipEntries } from '../zip'\nimport {\n assetKeyOf,\n assertDataMemberPath,\n assertModelMemberPath,\n assertSafeMemberPath,\n encodeMemberText,\n type ContainerManifest,\n type ContainerModel,\n} from './container'\n\n/** Assembly input of a container: no producer concept, only format concepts. */\nexport interface ContainerAssembly {\n /** `manifest.models` — the complete model list (spec §4) */\n models: ContainerModel[]\n /** `manifest.active`; must equal some `models[].id` when present */\n active?: string\n /** display-only manifest fields plus §8.2 conversion provenance */\n meta?: {\n createdAt?: string\n appVersion?: string\n label?: string\n source?: ContainerManifest['source']\n }\n /** `model/**` members: full container path → source text. Every `models[].entry` must be present */\n modules: Record<string, string>\n /** `data/**` members: full container path → JSON text (spec §6) */\n dataMembers: Record<string, string>\n /** `files/**` payloads: fileId → bytes. Written as `files/<fileId>.bin` */\n files: Record<string, Uint8Array>\n /** `assets/**` payloads: full container path → bytes (e.g. `assets/bracket.brp`) */\n assets: Record<string, Uint8Array>\n /** producer-defined members (spec §3, e.g. `mapping.json`, `freecad/**`), written as-is */\n producerMembers?: Record<string, Uint8Array>\n}\n\n/** Result of `writeContainer`. */\nexport interface WriteContainerResult {\n /** the assembled container bytes */\n bytes: Uint8Array\n /** the manifest that was serialized into the container */\n manifest: ContainerManifest\n}\n\nconst FILES_PREFIX = 'files/'\nconst ASSETS_PREFIX = 'assets/'\n\n/**\n * Build and validate the container manifest — the single implementation of the\n * §4 schema.\n *\n * Structural only: it cannot check that `models[].entry` and `models[].data`\n * resolve to emitted members, because it never sees the members. That is\n * `writeContainer`'s job, and it is why conversion pipelines that legitimately\n * assemble a container in two passes can still reuse this function.\n *\n * @param input the model list, the optional active id and display metadata\n * @returns the manifest, with `format: 3` and `units: \"mm\"` fixed\n * @throws when `models` is empty, an id/entry is empty, unsafe or duplicated,\n * an `entry` is not a module path under `model/` ending with `.fai.js`, a\n * `data` is not a JSON path under `data/`, or `active` names no model\n */\nexport function createManifest(input: Pick<ContainerAssembly, 'models' | 'active' | 'meta'>): ContainerManifest {\n const { models, active, meta = {} } = input\n if (!Array.isArray(models) || models.length === 0) {\n throw new Error('[fai-zip] createManifest: models must be a non-empty array')\n }\n\n const seenIds = new Set<string>()\n const seenEntries = new Set<string>()\n const normalized: ContainerModel[] = []\n for (let i = 0; i < models.length; i++) {\n const m = models[i] as ContainerModel\n const id = typeof m.id === 'string' ? m.id : ''\n if (id === '') throw new Error(`[fai-zip] createManifest: models[${i}].id must be a non-empty string`)\n if (id.includes('/') || id.includes('\\\\')) {\n throw new Error(`[fai-zip] createManifest: models[${i}].id must not contain \"/\" or \"\\\\\": \"${id}\"`)\n }\n if (seenIds.has(id)) throw new Error(`[fai-zip] createManifest: models[].id must be unique: \"${id}\"`)\n seenIds.add(id)\n\n if (typeof m.entry !== 'string' || m.entry === '') {\n throw new Error(`[fai-zip] createManifest: models[${i}].entry must be a non-empty string`)\n }\n assertModelMemberPath(m.entry, `createManifest: models[${i}].entry`)\n if (seenEntries.has(m.entry)) {\n throw new Error(`[fai-zip] createManifest: models[].entry must be unique: \"${m.entry}\"`)\n }\n seenEntries.add(m.entry)\n\n if (m.data !== undefined) assertDataMemberPath(m.data, `createManifest: models[${i}].data`)\n\n normalized.push({\n id,\n entry: m.entry,\n ...(m.label !== undefined ? { label: m.label } : {}),\n ...(m.data !== undefined ? { data: m.data } : {}),\n })\n }\n\n if (active !== undefined && !seenIds.has(active)) {\n throw new Error(`[fai-zip] createManifest: active must equal some models[].id: \"${active}\"`)\n }\n\n return {\n format: 3,\n units: 'mm',\n models: normalized,\n ...(active !== undefined ? { active } : {}),\n ...(meta.createdAt !== undefined ? { createdAt: meta.createdAt } : {}),\n ...(meta.appVersion !== undefined ? { appVersion: meta.appVersion } : {}),\n ...(meta.label !== undefined ? { label: meta.label } : {}),\n ...(meta.source !== undefined ? { source: meta.source } : {}),\n }\n}\n\n/**\n * Assemble a container from an assembly, enforcing spec §10 before writing any\n * bytes.\n *\n * Enforced (each throws, never silently produces an unreconstructable\n * container):\n * 1. `models` is non-empty, ids and entries are unique (`createManifest`);\n * 2. every `models[].entry` is emitted in `modules`;\n * 3. every `models[].data` is emitted in `dataMembers`;\n * 4. `active`, when present, equals some `models[].id` (`createManifest`);\n * 5. asset keys are unique across `files/**`, `assets/**` and any\n * producer-defined member in those namespaces (spec §7.1) — a fileId that\n * would not survive the base-name key rule is an error, not a silent rename;\n * 6. every `entry`/`data`/module/asset path is a safe relative member path in\n * its namespace, and no path is emitted twice.\n *\n * @param assembly the assembly input (§3.4)\n * @returns the container bytes and the manifest that was written\n * @throws when any of the obligations above is violated\n */\nexport function writeContainer(assembly: ContainerAssembly): WriteContainerResult {\n const { modules, dataMembers, files, assets, producerMembers = {} } = assembly\n const manifest = createManifest(assembly)\n\n const members = new Map<string, Uint8Array>()\n const claimedKeys = new Map<string, string>()\n\n /** Record an asset key; a second member claiming it is an error (spec §7.1). */\n const claim = (key: string, path: string): void => {\n const prev = claimedKeys.get(key)\n if (prev !== undefined) {\n throw new Error(`[fai-zip] writeContainer: duplicate asset key \"${key}\" (members \"${prev}\" and \"${path}\")`)\n }\n claimedKeys.set(key, path)\n }\n\n /** Add one member; a duplicate member path is an error. */\n const put = (path: string, body: Uint8Array): void => {\n if (members.has(path)) {\n throw new Error(`[fai-zip] writeContainer: duplicate member path \"${path}\"`)\n }\n members.set(path, body)\n }\n\n // manifest.json — always first, always present (spec §10.1)\n put('manifest.json', encodeMemberText(JSON.stringify(manifest, null, 2)))\n\n // model/** — every declared entry must be delivered (spec §10.2, §10.3)\n for (const [path, source] of Object.entries(modules)) {\n assertModelMemberPath(path, 'writeContainer: modules key')\n put(path, encodeMemberText(source))\n }\n for (const m of manifest.models) {\n if (!members.has(m.entry)) {\n throw new Error(`[fai-zip] writeContainer: models[].entry \"${m.entry}\" has no module in the assembly`)\n }\n }\n\n // data/** — a declared data member must be delivered, and must be JSON (spec §6.1)\n for (const [path, json] of Object.entries(dataMembers)) {\n assertDataMemberPath(path, 'writeContainer: dataMembers key')\n try {\n JSON.parse(json)\n } catch (e) {\n throw new Error(`[fai-zip] writeContainer: data member \"${path}\" is not valid JSON: ${e instanceof Error ? e.message : String(e)}`, { cause: e })\n }\n put(path, encodeMemberText(json))\n }\n for (const m of manifest.models) {\n if (m.data !== undefined && !members.has(m.data)) {\n throw new Error(`[fai-zip] writeContainer: models[].data \"${m.data}\" has no member in the assembly`)\n }\n }\n\n // files/** — keyed by fileId, stored as files/<fileId>.bin so the key\n // round-trips through the base-name rule (spec §7). A fileId containing a\n // separator would be silently re-keyed on read, so it is rejected here.\n for (const [fileId, body] of Object.entries(files)) {\n if (fileId === '' || fileId.includes('/') || fileId.includes('\\\\')) {\n throw new Error(`[fai-zip] writeContainer: fileId must be a non-empty base name without separators: \"${fileId}\"`)\n }\n const path = `${FILES_PREFIX}${fileId}.bin`\n put(path, body)\n claim(assetKeyOf(path, FILES_PREFIX), path)\n }\n\n // assets/** — the key is the base name, so two paths may collide (spec §7.1)\n for (const [path, body] of Object.entries(assets)) {\n assertSafeMemberPath(path, 'writeContainer: assets key')\n if (!path.startsWith(ASSETS_PREFIX)) {\n throw new Error(`[fai-zip] writeContainer: assets key must be under assets/: \"${path}\"`)\n }\n put(path, body)\n claim(assetKeyOf(path, ASSETS_PREFIX), path)\n }\n\n // producer-defined members (spec §3) — opaque payload, but they still live\n // in the archive, so a member dropped under files//assets/ takes part in the\n // key uniqueness rule whether or not the producer thought of it that way.\n for (const [path, body] of Object.entries(producerMembers)) {\n assertSafeMemberPath(path, 'writeContainer: producerMembers key')\n put(path, body)\n if (path.startsWith(FILES_PREFIX)) claim(assetKeyOf(path, FILES_PREFIX), path)\n else if (path.startsWith(ASSETS_PREFIX)) claim(assetKeyOf(path, ASSETS_PREFIX), path)\n }\n\n return { bytes: writeZipEntries(Object.fromEntries(members)), manifest }\n}\n"]}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.fai.zip` container schemas (docs/fai-zip-format.md §4, §7).
|
|
3
|
+
*
|
|
4
|
+
* `.fai.zip` is faijs' own container format, so this module carries the format
|
|
5
|
+
* itself and nothing producer-specific: `source` is a §4 manifest field
|
|
6
|
+
* (described in §8.2 as conversion provenance), not an FCStd leak. Producer
|
|
7
|
+
* members such as `mapping.json` and `freecad/**` are passed through opaquely
|
|
8
|
+
* (spec §3, "Optional, producer-defined"). `requiresBrep` was removed in
|
|
9
|
+
* 2026-10-03 (fai-zip-third-party-sdk-and-viewer-plan): BREP is always the
|
|
10
|
+
* default-required execution chain, so no per-container flag exists.
|
|
11
|
+
*
|
|
12
|
+
* Environment-independent by construction: no `node:*`, no DOM, no fflate.
|
|
13
|
+
* Text members go through the UTF-8 codec below, ZIP bytes go through
|
|
14
|
+
* `io/zip.ts` — the container layer never touches a ZIP library directly.
|
|
15
|
+
*/
|
|
16
|
+
/** One model in the container: entry script, plus an optional data member. */
|
|
17
|
+
export interface ContainerModel {
|
|
18
|
+
/** model identifier: unique in the container, stable (switch/data key), no `/` or `\` */
|
|
19
|
+
id: string;
|
|
20
|
+
/** container path of the model's entry script, inside `model/`, ends with `.fai.js` */
|
|
21
|
+
entry: string;
|
|
22
|
+
/** display name; a reader MUST NOT use it as an identifier (spec §4) */
|
|
23
|
+
label?: string;
|
|
24
|
+
/** container path of the model's data member; absent = no data member (spec §6.5) */
|
|
25
|
+
data?: string;
|
|
26
|
+
}
|
|
27
|
+
/** `manifest.json` schema (unified `.fai.zip` format v3, spec §4). */
|
|
28
|
+
export interface ContainerManifest {
|
|
29
|
+
/** container format identifier — MUST be 3 in this revision (spec §11) */
|
|
30
|
+
format: 3;
|
|
31
|
+
/** unit of every coordinate in the container; always "mm" */
|
|
32
|
+
units: 'mm';
|
|
33
|
+
/** the complete model list (length ≥ 1) */
|
|
34
|
+
models: ContainerModel[];
|
|
35
|
+
/** id of the initially active model; absent = `models[0]` */
|
|
36
|
+
active?: string;
|
|
37
|
+
/** ISO 8601 timestamp. Display only */
|
|
38
|
+
createdAt?: string;
|
|
39
|
+
/** version of the producing tool. Display only */
|
|
40
|
+
appVersion?: string;
|
|
41
|
+
/** container display name. Display only */
|
|
42
|
+
label?: string;
|
|
43
|
+
/** conversion provenance (spec §8.2). Display only */
|
|
44
|
+
source?: {
|
|
45
|
+
/** original source document file name (not a full path) */
|
|
46
|
+
file: string;
|
|
47
|
+
programVersion: string;
|
|
48
|
+
schemaVersion: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Asset payloads of a container: bytes keyed by asset key (spec §7).
|
|
53
|
+
* The key of a member is its base name with the final extension removed.
|
|
54
|
+
*/
|
|
55
|
+
export interface ContainerAssetEntries {
|
|
56
|
+
/** `files/**` members — key = fileId (member path under `files/` with the final extension removed) */
|
|
57
|
+
files: Record<string, Uint8Array>;
|
|
58
|
+
/** `assets/**` members — key = base name with the final extension removed */
|
|
59
|
+
assets: Record<string, Uint8Array>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Asset key of a member path: base name with the final extension removed
|
|
63
|
+
* (spec §7). `assets/bracket.brp` → `bracket`; `files/deep/9f1c2a.bin` →
|
|
64
|
+
* `9f1c2a`. The rule is by base name, so nesting does not change the key.
|
|
65
|
+
*
|
|
66
|
+
* @param path the container member path (including its namespace prefix)
|
|
67
|
+
* @param prefix the namespace prefix the path was matched against
|
|
68
|
+
* @returns the asset key
|
|
69
|
+
*/
|
|
70
|
+
export declare function assetKeyOf(path: string, prefix: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Decode a text member. UTF-8, matching the spec's "UTF-8 JSON object" wording.
|
|
73
|
+
* @param bytes the member bytes
|
|
74
|
+
* @returns the decoded text
|
|
75
|
+
*/
|
|
76
|
+
export declare function decodeMemberText(bytes: Uint8Array): string;
|
|
77
|
+
/**
|
|
78
|
+
* Encode a text member to UTF-8 bytes.
|
|
79
|
+
* @param text the member text
|
|
80
|
+
* @returns the encoded bytes
|
|
81
|
+
*/
|
|
82
|
+
export declare function encodeMemberText(text: string): Uint8Array;
|
|
83
|
+
/**
|
|
84
|
+
* Validate a member path against the spec §2 naming rules: relative, forward
|
|
85
|
+
* slashes only, no `..`, no drive letter, no leading `/`.
|
|
86
|
+
* @param path the member path to check
|
|
87
|
+
* @param what description of the field being checked, used in the error
|
|
88
|
+
* @throws when the path is not a safe relative member path
|
|
89
|
+
*/
|
|
90
|
+
export declare function assertSafeMemberPath(path: string, what: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* Validate that a path is a model entry/script member: under `model/` and
|
|
93
|
+
* ending with `.fai.js` (spec §5.1).
|
|
94
|
+
* @param path the member path to check
|
|
95
|
+
* @param what description of the field being checked, used in the error
|
|
96
|
+
* @throws when the path is not a model member path
|
|
97
|
+
*/
|
|
98
|
+
export declare function assertModelMemberPath(path: string, what: string): void;
|
|
99
|
+
/**
|
|
100
|
+
* Validate that a path is a data member path: under `data/` and ending with
|
|
101
|
+
* `.json` (spec §6.1).
|
|
102
|
+
* @param path the member path to check
|
|
103
|
+
* @param what description of the field being checked, used in the error
|
|
104
|
+
* @throws when the path is not a data member path
|
|
105
|
+
*/
|
|
106
|
+
export declare function assertDataMemberPath(path: string, what: string): void;
|
|
107
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../src/io/fai-zip/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAA;IACV,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAA;IACb,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,CAAA;IACT,6DAA6D;IAC7D,KAAK,EAAE,IAAI,CAAA;IACX,2CAA2C;IAC3C,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,MAAM,CAAC,EAAE;QACP,2DAA2D;QAC3D,IAAI,EAAE,MAAM,CAAA;QACZ,cAAc,EAAE,MAAM,CAAA;QACtB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,sGAAsG;IACtG,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACjC,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM/D;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEzD;AAKD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIrE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAKtE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAKrE"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.fai.zip` container schemas (docs/fai-zip-format.md §4, §7).
|
|
3
|
+
*
|
|
4
|
+
* `.fai.zip` is faijs' own container format, so this module carries the format
|
|
5
|
+
* itself and nothing producer-specific: `source` is a §4 manifest field
|
|
6
|
+
* (described in §8.2 as conversion provenance), not an FCStd leak. Producer
|
|
7
|
+
* members such as `mapping.json` and `freecad/**` are passed through opaquely
|
|
8
|
+
* (spec §3, "Optional, producer-defined"). `requiresBrep` was removed in
|
|
9
|
+
* 2026-10-03 (fai-zip-third-party-sdk-and-viewer-plan): BREP is always the
|
|
10
|
+
* default-required execution chain, so no per-container flag exists.
|
|
11
|
+
*
|
|
12
|
+
* Environment-independent by construction: no `node:*`, no DOM, no fflate.
|
|
13
|
+
* Text members go through the UTF-8 codec below, ZIP bytes go through
|
|
14
|
+
* `io/zip.ts` — the container layer never touches a ZIP library directly.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Asset key of a member path: base name with the final extension removed
|
|
18
|
+
* (spec §7). `assets/bracket.brp` → `bracket`; `files/deep/9f1c2a.bin` →
|
|
19
|
+
* `9f1c2a`. The rule is by base name, so nesting does not change the key.
|
|
20
|
+
*
|
|
21
|
+
* @param path the container member path (including its namespace prefix)
|
|
22
|
+
* @param prefix the namespace prefix the path was matched against
|
|
23
|
+
* @returns the asset key
|
|
24
|
+
*/
|
|
25
|
+
export function assetKeyOf(path, prefix) {
|
|
26
|
+
const rel = path.slice(prefix.length);
|
|
27
|
+
const slash = rel.lastIndexOf('/');
|
|
28
|
+
const base = slash >= 0 ? rel.slice(slash + 1) : rel;
|
|
29
|
+
const dot = base.lastIndexOf('.');
|
|
30
|
+
return dot > 0 ? base.slice(0, dot) : base;
|
|
31
|
+
}
|
|
32
|
+
const UTF8_DECODER = new TextDecoder('utf-8');
|
|
33
|
+
/**
|
|
34
|
+
* Decode a text member. UTF-8, matching the spec's "UTF-8 JSON object" wording.
|
|
35
|
+
* @param bytes the member bytes
|
|
36
|
+
* @returns the decoded text
|
|
37
|
+
*/
|
|
38
|
+
export function decodeMemberText(bytes) {
|
|
39
|
+
return UTF8_DECODER.decode(bytes);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Encode a text member to UTF-8 bytes.
|
|
43
|
+
* @param text the member text
|
|
44
|
+
* @returns the encoded bytes
|
|
45
|
+
*/
|
|
46
|
+
export function encodeMemberText(text) {
|
|
47
|
+
return new TextEncoder().encode(text);
|
|
48
|
+
}
|
|
49
|
+
const MODEL_PREFIX = 'model/';
|
|
50
|
+
const DATA_PREFIX = 'data/';
|
|
51
|
+
/**
|
|
52
|
+
* Validate a member path against the spec §2 naming rules: relative, forward
|
|
53
|
+
* slashes only, no `..`, no drive letter, no leading `/`.
|
|
54
|
+
* @param path the member path to check
|
|
55
|
+
* @param what description of the field being checked, used in the error
|
|
56
|
+
* @throws when the path is not a safe relative member path
|
|
57
|
+
*/
|
|
58
|
+
export function assertSafeMemberPath(path, what) {
|
|
59
|
+
if (path === '' || path.startsWith('/') || path.includes('\\') || path.includes('..') || /^[A-Za-z]:/.test(path)) {
|
|
60
|
+
throw new Error(`[fai-zip] unsafe member path in ${what}: "${path}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate that a path is a model entry/script member: under `model/` and
|
|
65
|
+
* ending with `.fai.js` (spec §5.1).
|
|
66
|
+
* @param path the member path to check
|
|
67
|
+
* @param what description of the field being checked, used in the error
|
|
68
|
+
* @throws when the path is not a model member path
|
|
69
|
+
*/
|
|
70
|
+
export function assertModelMemberPath(path, what) {
|
|
71
|
+
assertSafeMemberPath(path, what);
|
|
72
|
+
if (!path.startsWith(MODEL_PREFIX) || !path.endsWith('.fai.js')) {
|
|
73
|
+
throw new Error(`[fai-zip] ${what} must be under model/ and end with .fai.js: "${path}"`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate that a path is a data member path: under `data/` and ending with
|
|
78
|
+
* `.json` (spec §6.1).
|
|
79
|
+
* @param path the member path to check
|
|
80
|
+
* @param what description of the field being checked, used in the error
|
|
81
|
+
* @throws when the path is not a data member path
|
|
82
|
+
*/
|
|
83
|
+
export function assertDataMemberPath(path, what) {
|
|
84
|
+
assertSafeMemberPath(path, what);
|
|
85
|
+
if (!path.startsWith(DATA_PREFIX) || !path.endsWith('.json')) {
|
|
86
|
+
throw new Error(`[fai-zip] ${what} must be under data/ and end with .json: "${path}"`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../../src/io/fai-zip/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAkDH;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAc;IACrD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAClC,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACjC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC5C,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAA;AAE7C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,OAAO,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,YAAY,GAAG,QAAQ,CAAA;AAC7B,MAAM,WAAW,GAAG,OAAO,CAAA;AAE3B;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,IAAY;IAC7D,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjH,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAA;IACvE,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,IAAY;IAC9D,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,gDAAgD,IAAI,GAAG,CAAC,CAAA;IAC3F,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,IAAY;IAC7D,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAChC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,6CAA6C,IAAI,GAAG,CAAC,CAAA;IACxF,CAAC;AACH,CAAC","sourcesContent":["/**\n * `.fai.zip` container schemas (docs/fai-zip-format.md §4, §7).\n *\n * `.fai.zip` is faijs' own container format, so this module carries the format\n * itself and nothing producer-specific: `source` is a §4 manifest field\n * (described in §8.2 as conversion provenance), not an FCStd leak. Producer\n * members such as `mapping.json` and `freecad/**` are passed through opaquely\n * (spec §3, \"Optional, producer-defined\"). `requiresBrep` was removed in\n * 2026-10-03 (fai-zip-third-party-sdk-and-viewer-plan): BREP is always the\n * default-required execution chain, so no per-container flag exists.\n *\n * Environment-independent by construction: no `node:*`, no DOM, no fflate.\n * Text members go through the UTF-8 codec below, ZIP bytes go through\n * `io/zip.ts` — the container layer never touches a ZIP library directly.\n */\n\n/** One model in the container: entry script, plus an optional data member. */\nexport interface ContainerModel {\n /** model identifier: unique in the container, stable (switch/data key), no `/` or `\\` */\n id: string\n /** container path of the model's entry script, inside `model/`, ends with `.fai.js` */\n entry: string\n /** display name; a reader MUST NOT use it as an identifier (spec §4) */\n label?: string\n /** container path of the model's data member; absent = no data member (spec §6.5) */\n data?: string\n}\n\n/** `manifest.json` schema (unified `.fai.zip` format v3, spec §4). */\nexport interface ContainerManifest {\n /** container format identifier — MUST be 3 in this revision (spec §11) */\n format: 3\n /** unit of every coordinate in the container; always \"mm\" */\n units: 'mm'\n /** the complete model list (length ≥ 1) */\n models: ContainerModel[]\n /** id of the initially active model; absent = `models[0]` */\n active?: string\n /** ISO 8601 timestamp. Display only */\n createdAt?: string\n /** version of the producing tool. Display only */\n appVersion?: string\n /** container display name. Display only */\n label?: string\n /** conversion provenance (spec §8.2). Display only */\n source?: {\n /** original source document file name (not a full path) */\n file: string\n programVersion: string\n schemaVersion: number\n }\n}\n\n/**\n * Asset payloads of a container: bytes keyed by asset key (spec §7).\n * The key of a member is its base name with the final extension removed.\n */\nexport interface ContainerAssetEntries {\n /** `files/**` members — key = fileId (member path under `files/` with the final extension removed) */\n files: Record<string, Uint8Array>\n /** `assets/**` members — key = base name with the final extension removed */\n assets: Record<string, Uint8Array>\n}\n\n/**\n * Asset key of a member path: base name with the final extension removed\n * (spec §7). `assets/bracket.brp` → `bracket`; `files/deep/9f1c2a.bin` →\n * `9f1c2a`. The rule is by base name, so nesting does not change the key.\n *\n * @param path the container member path (including its namespace prefix)\n * @param prefix the namespace prefix the path was matched against\n * @returns the asset key\n */\nexport function assetKeyOf(path: string, prefix: string): string {\n const rel = path.slice(prefix.length)\n const slash = rel.lastIndexOf('/')\n const base = slash >= 0 ? rel.slice(slash + 1) : rel\n const dot = base.lastIndexOf('.')\n return dot > 0 ? base.slice(0, dot) : base\n}\n\nconst UTF8_DECODER = new TextDecoder('utf-8')\n\n/**\n * Decode a text member. UTF-8, matching the spec's \"UTF-8 JSON object\" wording.\n * @param bytes the member bytes\n * @returns the decoded text\n */\nexport function decodeMemberText(bytes: Uint8Array): string {\n return UTF8_DECODER.decode(bytes)\n}\n\n/**\n * Encode a text member to UTF-8 bytes.\n * @param text the member text\n * @returns the encoded bytes\n */\nexport function encodeMemberText(text: string): Uint8Array {\n return new TextEncoder().encode(text)\n}\n\nconst MODEL_PREFIX = 'model/'\nconst DATA_PREFIX = 'data/'\n\n/**\n * Validate a member path against the spec §2 naming rules: relative, forward\n * slashes only, no `..`, no drive letter, no leading `/`.\n * @param path the member path to check\n * @param what description of the field being checked, used in the error\n * @throws when the path is not a safe relative member path\n */\nexport function assertSafeMemberPath(path: string, what: string): void {\n if (path === '' || path.startsWith('/') || path.includes('\\\\') || path.includes('..') || /^[A-Za-z]:/.test(path)) {\n throw new Error(`[fai-zip] unsafe member path in ${what}: \"${path}\"`)\n }\n}\n\n/**\n * Validate that a path is a model entry/script member: under `model/` and\n * ending with `.fai.js` (spec §5.1).\n * @param path the member path to check\n * @param what description of the field being checked, used in the error\n * @throws when the path is not a model member path\n */\nexport function assertModelMemberPath(path: string, what: string): void {\n assertSafeMemberPath(path, what)\n if (!path.startsWith(MODEL_PREFIX) || !path.endsWith('.fai.js')) {\n throw new Error(`[fai-zip] ${what} must be under model/ and end with .fai.js: \"${path}\"`)\n }\n}\n\n/**\n * Validate that a path is a data member path: under `data/` and ending with\n * `.json` (spec §6.1).\n * @param path the member path to check\n * @param what description of the field being checked, used in the error\n * @throws when the path is not a data member path\n */\nexport function assertDataMemberPath(path: string, what: string): void {\n assertSafeMemberPath(path, what)\n if (!path.startsWith(DATA_PREFIX) || !path.endsWith('.json')) {\n throw new Error(`[fai-zip] ${what} must be under data/ and end with .json: \"${path}\"`)\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@faicad/faijs/io/fai-zip` — the `.fai.zip` container layer.
|
|
3
|
+
*
|
|
4
|
+
* `.fai.zip` is faijs' own container format (docs/fai-zip-format.md). Reading,
|
|
5
|
+
* writing and the manifest schema live here, in core, because every host that
|
|
6
|
+
* loads or saves a faijs project needs them and none of them needs a
|
|
7
|
+
* producer-specific converter to get at them.
|
|
8
|
+
*
|
|
9
|
+
* The layer is a peer of `@faicad/faijs/io`, not a child of it: `io` owns ZIP
|
|
10
|
+
* bytes, this owns the container format built on top. `io/index.ts` therefore
|
|
11
|
+
* does not re-export anything from here — a base layer never depends on a
|
|
12
|
+
* format layer.
|
|
13
|
+
*/
|
|
14
|
+
export type { ContainerAssetEntries, ContainerManifest, ContainerModel } from './container.js';
|
|
15
|
+
export { decodeMemberText, encodeMemberText } from './container.js';
|
|
16
|
+
export { listModels, listModules, openContainer, readAssetEntries, readDataMember, readManifest, readModule, type OpenContainerOptions, type OpenContainerResult, } from './container-read.js';
|
|
17
|
+
export { createManifest, writeContainer, type ContainerAssembly, type WriteContainerResult, } from './container-write.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/io/fai-zip/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC3F,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EACL,UAAU,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,UAAU,EACV,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,cAAc,EACd,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { decodeMemberText, encodeMemberText } from './container.js';
|
|
2
|
+
export { listModels, listModules, openContainer, readAssetEntries, readDataMember, readManifest, readModule, } from './container-read.js';
|
|
3
|
+
export { createManifest, writeContainer, } from './container-write.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/io/fai-zip/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EACL,UAAU,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,UAAU,GAGX,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,cAAc,EACd,cAAc,GAGf,MAAM,mBAAmB,CAAA","sourcesContent":["/**\n * `@faicad/faijs/io/fai-zip` — the `.fai.zip` container layer.\n *\n * `.fai.zip` is faijs' own container format (docs/fai-zip-format.md). Reading,\n * writing and the manifest schema live here, in core, because every host that\n * loads or saves a faijs project needs them and none of them needs a\n * producer-specific converter to get at them.\n *\n * The layer is a peer of `@faicad/faijs/io`, not a child of it: `io` owns ZIP\n * bytes, this owns the container format built on top. `io/index.ts` therefore\n * does not re-export anything from here — a base layer never depends on a\n * format layer.\n */\nexport type { ContainerAssetEntries, ContainerManifest, ContainerModel } from './container'\nexport { decodeMemberText, encodeMemberText } from './container'\nexport {\n listModels,\n listModules,\n openContainer,\n readAssetEntries,\n readDataMember,\n readManifest,\n readModule,\n type OpenContainerOptions,\n type OpenContainerResult,\n} from './container-read'\nexport {\n createManifest,\n writeContainer,\n type ContainerAssembly,\n type WriteContainerResult,\n} from './container-write'\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* io — unified ZIP container IO for faijs (and the host).
|
|
3
|
+
*
|
|
4
|
+
* Single read/write entry for ZIP bytes; every downstream consumer (3MF loader,
|
|
5
|
+
* export-model writer, fcstd, demo) should use these rather than fflate
|
|
6
|
+
* directly. See `io/zip.ts` for the behaviour contract.
|
|
7
|
+
*/
|
|
8
|
+
export { readZipEntries, readZipEntriesAsync, writeZipEntries, writeZipEntriesAsync, DEFAULT_MAX_ENTRIES, DEFAULT_MAX_TOTAL_BYTES, type ZipReadOptions, } from './zip.js';
|
|
9
|
+
export { toArrayBuffer } from './bytes.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/io/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,cAAc,GACpB,MAAM,OAAO,CAAA;AAId,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA"}
|