@spinekit/media 0.1.1 → 0.1.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 - 2026-08-22
4
+
5
+ ### Added
6
+
7
+ - **`buildTransformPolicy(input?)`** — derives the `MediaTransformPolicy` document served to clients directly from the server's own `SIZE_VARIANTS`, `FOLDER_CONTENT_TYPE_MAP`, and `IMAGE_SETTINGS`. Previously each client surface (browser, mobile app, importer) held its own folder → preset table that could silently diverge from the server. The derived policy is authoritative: change the server defaults and every client resolves the same rules automatically. Untouched-folder overrides and a max-edge override are supported via `TransformPolicyInput`. Uses `@classytic/media-transform/policy` for the document shape and version constant.
8
+
9
+ - **Cleanup steps** (`src/cleanup.ts`) — `CleanupStep` implementations for the three media purge operations (purge deleted, purge stale-pending, purge expired). Exporting as steps makes the same operations previewable (`estimate` before touching anything), confirmable, cancellable between steps, and auditable via arc's Cleanup Center (`PurgeEvidence` manifest). Contract is `@classytic/repo-core/cleanup` — no arc host-framework dependency, fold into a recipe with `recipeFromSteps()`.
10
+
3
11
  ## 0.1.1 - 2026-08-21
4
12
 
5
13
  ### Changed
@@ -5,10 +5,14 @@ interface S3ProviderConfig {
5
5
  kind: 's3';
6
6
  bucket: string;
7
7
  region: string;
8
- accessKeyId: string;
9
- secretAccessKey: string;
8
+ /** Omit both fields to use the deployment platform's default AWS credential chain. */
9
+ accessKeyId?: string;
10
+ secretAccessKey?: string;
11
+ /** Custom endpoint for S3-compatible services such as R2, MinIO, or Spaces. */
12
+ endpoint?: string;
10
13
  publicUrl?: string;
11
- acl?: string;
14
+ acl?: 'private' | 'public-read' | 'authenticated-read';
15
+ forcePathStyle?: boolean;
12
16
  }
13
17
  interface GcsProviderConfig {
14
18
  kind: 'gcs';
@@ -17,6 +21,8 @@ interface GcsProviderConfig {
17
21
  keyFilename?: string;
18
22
  credentials?: Record<string, unknown>;
19
23
  publicUrl?: string;
24
+ /** Private by default. Set true only for an intentionally public media deployment. */
25
+ makePublic?: boolean;
20
26
  }
21
27
  interface CloudflareImagesProviderConfig {
22
28
  kind: 'cloudflare-images';
@@ -1,12 +1,7 @@
1
1
  //#region src/providers/media-provider.config.ts
2
2
  /** Required credential fields per provider — the completeness check is data, not code. */
3
3
  const REQUIRED = {
4
- s3: [
5
- "bucket",
6
- "region",
7
- "accessKeyId",
8
- "secretAccessKey"
9
- ],
4
+ s3: ["bucket", "region"],
10
5
  gcs: ["bucket"],
11
6
  "cloudflare-images": ["accountId", "apiToken"],
12
7
  cloudinary: [
@@ -36,10 +31,15 @@ const SECRET_FIELDS = /* @__PURE__ */ new Set([
36
31
  function missingProviderFields(config) {
37
32
  const required = REQUIRED[config.kind] ?? [];
38
33
  const bag = config;
39
- return required.filter((f) => {
34
+ const missing = required.filter((f) => {
40
35
  const v = bag[f];
41
36
  return v === void 0 || v === null || v === "";
42
37
  });
38
+ if (config.kind === "s3") {
39
+ const hasAccessKey = Boolean(config.accessKeyId);
40
+ if (hasAccessKey !== Boolean(config.secretAccessKey)) missing.push(hasAccessKey ? "secretAccessKey" : "accessKeyId");
41
+ }
42
+ return missing;
43
43
  }
44
44
  async function resolveMediaProvider(config, options = {}) {
45
45
  if (!config || missingProviderFields(config).length > 0) {
@@ -53,17 +53,23 @@ async function resolveMediaProvider(config, options = {}) {
53
53
  return new S3Provider({
54
54
  bucket: config.bucket,
55
55
  region: config.region,
56
- credentials: {
56
+ ...config.accessKeyId && config.secretAccessKey ? { credentials: {
57
57
  accessKeyId: config.accessKeyId,
58
58
  secretAccessKey: config.secretAccessKey
59
- },
59
+ } } : {},
60
+ ...config.endpoint ? { endpoint: config.endpoint } : {},
60
61
  ...config.publicUrl ? { publicUrl: config.publicUrl } : {},
61
- ...config.acl ? { acl: config.acl } : {}
62
+ ...config.acl ? { acl: config.acl } : {},
63
+ ...config.forcePathStyle !== void 0 ? { forcePathStyle: config.forcePathStyle } : {}
62
64
  });
63
65
  }
64
66
  case "gcs": {
65
67
  const { GCSProvider } = await import("@classytic/media-kit/providers/gcs");
66
- return new GCSProvider({ ...config });
68
+ const { kind: _kind, ...providerConfig } = config;
69
+ return new GCSProvider({
70
+ makePublic: false,
71
+ ...providerConfig
72
+ });
67
73
  }
68
74
  case "cloudflare-images": {
69
75
  const { CloudflareImagesProvider } = await import("@classytic/media-kit/providers/cloudflare-images");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spinekit/media",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Arc module for @classytic/media-kit — two-phase direct-to-storage uploads (start-write / complete-write), content-hash dedup handshake, multipart & resumable sessions, and maintenance schedules, as ONE composable Arc resource.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -74,7 +74,7 @@
74
74
  "typescript": "^7.0.2",
75
75
  "vitest": "^3.2.4",
76
76
  "zod": "^4.0.0",
77
- "@spinekit/kit": "0.1.0"
77
+ "@spinekit/kit": "0.1.1"
78
78
  },
79
79
  "author": "Classytic",
80
80
  "homepage": "https://www.npmjs.com/package/@spinekit/media",