@flaghoist/server 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard.cjs +1 -1
- package/dist/dashboard.js +1 -1
- package/dist/index.cjs +23 -9
- package/dist/index.js +23 -9
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -64,7 +64,10 @@ function buildFlag(key, body, identity, existing) {
|
|
|
64
64
|
return { ok: false, error: `Description exceeds ${import_core.LIMITS.maxDescriptionLength} characters` };
|
|
65
65
|
}
|
|
66
66
|
const inputRules = Array.isArray(b.rules) ? b.rules : [];
|
|
67
|
-
const
|
|
67
|
+
const nowMs = Date.now();
|
|
68
|
+
const prevMs = existing ? Date.parse(existing.metadata.updatedAt) : 0;
|
|
69
|
+
const updatedAt = new Date(nowMs > prevMs ? nowMs : prevMs + 1).toISOString();
|
|
70
|
+
const createdAt = existing?.metadata.createdAt ?? new Date(nowMs).toISOString();
|
|
68
71
|
const candidate = {
|
|
69
72
|
key,
|
|
70
73
|
enabled,
|
|
@@ -73,9 +76,9 @@ function buildFlag(key, body, identity, existing) {
|
|
|
73
76
|
description,
|
|
74
77
|
metadata: {
|
|
75
78
|
createdBy: existing?.metadata.createdBy ?? identity,
|
|
76
|
-
createdAt
|
|
79
|
+
createdAt,
|
|
77
80
|
updatedBy: identity,
|
|
78
|
-
updatedAt
|
|
81
|
+
updatedAt
|
|
79
82
|
}
|
|
80
83
|
};
|
|
81
84
|
const validated = (0, import_core.parseFlag)(candidate);
|
|
@@ -85,6 +88,9 @@ function buildFlag(key, body, identity, existing) {
|
|
|
85
88
|
}
|
|
86
89
|
return { ok: true, flag: validated };
|
|
87
90
|
}
|
|
91
|
+
function flagEtag(flag) {
|
|
92
|
+
return `"${flag.metadata.updatedAt}"`;
|
|
93
|
+
}
|
|
88
94
|
|
|
89
95
|
// src/openapi.ts
|
|
90
96
|
var openApiDocument = {
|
|
@@ -690,6 +696,7 @@ function createFlagServer(config) {
|
|
|
690
696
|
if (!auth.ok) return c.json({ error: auth.message ?? "Unauthorized" }, auth.status ?? 401);
|
|
691
697
|
const flag = await cfg.storage.get(c.req.param("key"));
|
|
692
698
|
if (!flag) return c.json({ error: "Flag not found" }, 404);
|
|
699
|
+
c.header("ETag", flagEtag(flag));
|
|
693
700
|
return c.json(flag);
|
|
694
701
|
});
|
|
695
702
|
app.put(`${prefix}/flags/:key`, async (c) => {
|
|
@@ -697,17 +704,24 @@ function createFlagServer(config) {
|
|
|
697
704
|
const auth = await cfg.auth.admin(c.req.raw.headers);
|
|
698
705
|
if (!auth.ok) return c.json({ error: auth.message ?? "Unauthorized" }, auth.status ?? 401);
|
|
699
706
|
const key = c.req.param("key");
|
|
707
|
+
const existing = await cfg.storage.get(key);
|
|
708
|
+
const ifMatch = c.req.header("If-Match")?.trim();
|
|
709
|
+
if (ifMatch !== void 0) {
|
|
710
|
+
const precondition = ifMatch === "*" ? existing !== null : existing !== null && flagEtag(existing) === ifMatch;
|
|
711
|
+
if (!precondition) {
|
|
712
|
+
return c.json(
|
|
713
|
+
{ error: "This flag changed since you loaded it. Reload and reapply your change." },
|
|
714
|
+
412
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
700
718
|
const parsed = await readJsonBody(await c.req.text());
|
|
701
719
|
if (!parsed.ok) return c.json({ error: parsed.message }, parsed.status);
|
|
702
|
-
const built = buildFlag(
|
|
703
|
-
key,
|
|
704
|
-
parsed.value,
|
|
705
|
-
auth.identity ?? "unknown",
|
|
706
|
-
await cfg.storage.get(key)
|
|
707
|
-
);
|
|
720
|
+
const built = buildFlag(key, parsed.value, auth.identity ?? "unknown", existing);
|
|
708
721
|
if (!built.ok) return c.json({ error: built.error }, 400);
|
|
709
722
|
await cfg.storage.put(key, built.flag);
|
|
710
723
|
cache.invalidate();
|
|
724
|
+
c.header("ETag", flagEtag(built.flag));
|
|
711
725
|
return c.json(built.flag);
|
|
712
726
|
});
|
|
713
727
|
app.delete(`${prefix}/flags/:key`, async (c) => {
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,10 @@ function buildFlag(key, body, identity, existing) {
|
|
|
34
34
|
return { ok: false, error: `Description exceeds ${LIMITS.maxDescriptionLength} characters` };
|
|
35
35
|
}
|
|
36
36
|
const inputRules = Array.isArray(b.rules) ? b.rules : [];
|
|
37
|
-
const
|
|
37
|
+
const nowMs = Date.now();
|
|
38
|
+
const prevMs = existing ? Date.parse(existing.metadata.updatedAt) : 0;
|
|
39
|
+
const updatedAt = new Date(nowMs > prevMs ? nowMs : prevMs + 1).toISOString();
|
|
40
|
+
const createdAt = existing?.metadata.createdAt ?? new Date(nowMs).toISOString();
|
|
38
41
|
const candidate = {
|
|
39
42
|
key,
|
|
40
43
|
enabled,
|
|
@@ -43,9 +46,9 @@ function buildFlag(key, body, identity, existing) {
|
|
|
43
46
|
description,
|
|
44
47
|
metadata: {
|
|
45
48
|
createdBy: existing?.metadata.createdBy ?? identity,
|
|
46
|
-
createdAt
|
|
49
|
+
createdAt,
|
|
47
50
|
updatedBy: identity,
|
|
48
|
-
updatedAt
|
|
51
|
+
updatedAt
|
|
49
52
|
}
|
|
50
53
|
};
|
|
51
54
|
const validated = parseFlag(candidate);
|
|
@@ -55,6 +58,9 @@ function buildFlag(key, body, identity, existing) {
|
|
|
55
58
|
}
|
|
56
59
|
return { ok: true, flag: validated };
|
|
57
60
|
}
|
|
61
|
+
function flagEtag(flag) {
|
|
62
|
+
return `"${flag.metadata.updatedAt}"`;
|
|
63
|
+
}
|
|
58
64
|
|
|
59
65
|
// src/openapi.ts
|
|
60
66
|
var openApiDocument = {
|
|
@@ -660,6 +666,7 @@ function createFlagServer(config) {
|
|
|
660
666
|
if (!auth.ok) return c.json({ error: auth.message ?? "Unauthorized" }, auth.status ?? 401);
|
|
661
667
|
const flag = await cfg.storage.get(c.req.param("key"));
|
|
662
668
|
if (!flag) return c.json({ error: "Flag not found" }, 404);
|
|
669
|
+
c.header("ETag", flagEtag(flag));
|
|
663
670
|
return c.json(flag);
|
|
664
671
|
});
|
|
665
672
|
app.put(`${prefix}/flags/:key`, async (c) => {
|
|
@@ -667,17 +674,24 @@ function createFlagServer(config) {
|
|
|
667
674
|
const auth = await cfg.auth.admin(c.req.raw.headers);
|
|
668
675
|
if (!auth.ok) return c.json({ error: auth.message ?? "Unauthorized" }, auth.status ?? 401);
|
|
669
676
|
const key = c.req.param("key");
|
|
677
|
+
const existing = await cfg.storage.get(key);
|
|
678
|
+
const ifMatch = c.req.header("If-Match")?.trim();
|
|
679
|
+
if (ifMatch !== void 0) {
|
|
680
|
+
const precondition = ifMatch === "*" ? existing !== null : existing !== null && flagEtag(existing) === ifMatch;
|
|
681
|
+
if (!precondition) {
|
|
682
|
+
return c.json(
|
|
683
|
+
{ error: "This flag changed since you loaded it. Reload and reapply your change." },
|
|
684
|
+
412
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
670
688
|
const parsed = await readJsonBody(await c.req.text());
|
|
671
689
|
if (!parsed.ok) return c.json({ error: parsed.message }, parsed.status);
|
|
672
|
-
const built = buildFlag(
|
|
673
|
-
key,
|
|
674
|
-
parsed.value,
|
|
675
|
-
auth.identity ?? "unknown",
|
|
676
|
-
await cfg.storage.get(key)
|
|
677
|
-
);
|
|
690
|
+
const built = buildFlag(key, parsed.value, auth.identity ?? "unknown", existing);
|
|
678
691
|
if (!built.ok) return c.json({ error: built.error }, 400);
|
|
679
692
|
await cfg.storage.put(key, built.flag);
|
|
680
693
|
cache.invalidate();
|
|
694
|
+
c.header("ETag", flagEtag(built.flag));
|
|
681
695
|
return c.json(built.flag);
|
|
682
696
|
});
|
|
683
697
|
app.delete(`${prefix}/flags/:key`, async (c) => {
|